Java 8 - 在stream.map()中链接构造函数调用和setter

use*_*547 32 java lambda java-8 java-stream

我上课了

class Foo{
    String name;
    // setter, getter
}
Run Code Online (Sandbox Code Playgroud)

它只有一个默认的构造函数.

然后,我试图Foo从一些字符串创建一个List :

Arrays.stream(fooString.split(","))
            .map(name -> {
                Foo x = new Foo();
                x.setName(name);
                return x;

            }).collect(Collectors.toList()));
Run Code Online (Sandbox Code Playgroud)

由于没有构造函数采用名称,我不能简单地使用方法引用.当然,我可以使用构造函数调用和setter将这三行提取到一个方法中,但有没有更好或简洁的方法呢?(不更改Foo,这是生成的文件)

Hol*_*ger 32

如果这种情况反复发生,您可以创建一个通用实用程序方法来处理给定一个属性值的构造对象的问题:

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;
    };
}
Run Code Online (Sandbox Code Playgroud)

然后你可以使用它像:

List<Foo> l = Arrays.stream(fooString.split(","))
    .map(create(Foo::new, Foo::setName)).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

注意这不是特定的,Foo也不是它的setName方法:

List<List<String>> l = Arrays.stream(fooString.split(","))
    .map(create(ArrayList<String>::new, List::add)).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

顺便说一句,如果fooString变得非常大和/或可能包含许多元素(分裂后),使用它Pattern.compile(",").splitAsStream(fooString)代替可能更有效Arrays.stream(fooString.split(",")).


Tun*_*aki 11

不,没有更好的方法.

唯一的选择是,就像你在你的问题中所说的那样,为Foo对象创建一个工厂:

public class FooFactory {
    public static Foo fromName(String name) {
        Foo foo = new Foo();
        foo.setName(name);
        return foo;
    }
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

Arrays.stream(fooString.split(",")).map(FooFactory::fromName).collect(toList());
Run Code Online (Sandbox Code Playgroud)

如果要分割很多名称,则可以使用Pattern.compile(",").splitAsStream(fooString)(并将编译后的模式存储在常量中以避免重新创建)而不是Arrays.stream(fooString.split(",")).


ale*_*oot 8

在这种情况下,除非您添加以名称作为参数的构造函数,否则您没有太多选择,或者您创建了一个创建实例的静态工厂方法.


Phi*_*ipp 5

.map(n -> new Foo() {{ name = n; }} )

这使用初始化块来设置实例变量。

然而有一个警告:返回的对象实际上不是类型,Foo而是扩展的新的匿名类Foo。当您遵循里氏替换原则时,这应该不是问题,但在某些情况下可能会引起问题。