[英]Java 8 - chaining constructor call and setter in stream.map()
我上課了
class Foo{
String name;
// setter, getter
}
它只有一個默認的構造函數。
然后,我試圖從一些字符串創建一個Foo
列表:
Arrays.stream(fooString.split(","))
.map(name -> {
Foo x = new Foo();
x.setName(name);
return x;
}).collect(Collectors.toList()));
由於沒有構造函數采用名稱,我不能簡單地使用方法引用。 當然,我可以使用構造函數調用和setter將這三行提取到一個方法中,但有沒有更好或簡潔的方法呢? (不改變Foo
,這是一個生成的文件)
如果這種情況反復發生,您可以創建一個通用實用程序方法來處理給定一個屬性值的構造對象的問題:
public static <T,V> Function<V,T> create(
Supplier<? extends T> constructor, BiConsumer<? super T, ? super V> setter) {
return v -> {
T t=constructor.get();
setter.accept(t, v);
return t;
};
}
然后你可以使用它像:
List<Foo> l = Arrays.stream(fooString.split(","))
.map(create(Foo::new, Foo::setName)).collect(Collectors.toList());
注意這不是特定於Foo
及其setName
方法:
List<List<String>> l = Arrays.stream(fooString.split(","))
.map(create(ArrayList<String>::new, List::add)).collect(Collectors.toList());
順便說一句,如果fooString
變得非常大和/或可能包含很多元素(在拆分之后),使用Pattern.compile(",").splitAsStream(fooString)
而不是Arrays.stream(fooString.split(","))
Pattern.compile(",").splitAsStream(fooString)
可能更有效Arrays.stream(fooString.split(","))
。
不,沒有更好的方法。
唯一的選擇是,就像你在你的問題中所說的那樣,為Foo
對象創建一個工廠:
public class FooFactory {
public static Foo fromName(String name) {
Foo foo = new Foo();
foo.setName(name);
return foo;
}
}
並像這樣使用它:
Arrays.stream(fooString.split(",")).map(FooFactory::fromName).collect(toList());
如果要拆分很多名稱,可以使用Pattern.compile(",").splitAsStream(fooString)
(並將編譯后的模式存儲在常量中以避免重新創建)而不是Arrays.stream(fooString.split(","))
。
在這種情況下,除非您添加以名稱作為參數的構造函數,否則您沒有太多選擇,或者您創建了一個創建實例的靜態工廠方法 。
.map(n -> new Foo() {{ name = n; }} )
這使用初始化塊來設置實例變量。
但是有一個警告:返回的對象實際上不是Foo
類型,而是擴展Foo
的新的匿名類。 當你遵循Liskov替換原則時,這不應該是一個問題,但有一些情況可能是一個問題。
另一個沒人提到的替代方案是將Foo
類子類化,但是這可能有一些缺點 - 很難說它是否適合解決你的問題,因為我不知道上下文。
public class Bar extends Foo {
public Bar(String name) {
super.setName(name);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.