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

2022-09-01 06:42:44

我有一个班级

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


答案 1

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

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());

请注意,这并不是特定于其方法的:FoosetName

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

顺便说一句,如果变得非常大和/或可能包含大量元素(拆分后),则使用它可能会比 .fooStringPattern.compile(",").splitAsStream(fooString)Arrays.stream(fooString.split(","))


答案 2

不,没有更好的方法。

唯一的选择是,就像你在问题中所说的那样,为对象创建一个工厂: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(","))


推荐