2015-11-04 14 views
25

私はちょうどデフォルトコンストラクタを持つクラスのJava 8 - 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())); 

名前を取るコンストラクタがありませんので、私は単純にメソッド参照を使用することはできません。もちろん、私はコンストラクタコールとセッターを使ってメソッドに3行を抽出することができましたが、それを行うためのより良いまたは簡潔な方法がありますか?

+0

ストリームにジップがあった場合... – njzk2

答えて

24

この問題が繰り返し発生する場合は、あなたが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()); 

注意これがどのようにしてFooでもsetNameの方法に特有でないのか:

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

ところで、fooStringが非常に大きくなったり、(分割後に)たくさんの要素を含む場合は、Arrays.stream(fooString.split(","))の代わりにPattern.compile(",").splitAsStream(fooString)を使用する方が効率的かもしれません。

8

この場合、名前をパラメータとして使用するコンストラクタを追加したり、インスタンスを作成するstatic factory methodを作成しない限り、代替案があまりにも多くありません。

11

いいえ、いい方法はありません。

、あなたの質問に言ったように唯一の選択肢は、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(","))の代わりに使用できます。

3

もう1つの選択肢は、Fooクラスをサブクラス化することですが、これにはいくつかの短所があるかもしれません。コンテキストがわからないため、問題が適切な解決策になるかどうかは分かりません。

public class Bar extends Foo { 

    public Bar(String name) { 
     super.setName(name); 
    } 

} 
3

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

これは、インスタンス変数を設定する初期化ブロックを使用します。

ただし、警告があります。返されるオブジェクトのタイプは、実際にはFooではなく、Fooに拡張された新しい匿名クラスです。あなたがLiskov置換原則に従うとき、これは問題ではありませんが、それが懸念されるいくつかの状況があります。

+0

...または:.map(n - > new Foo(){{setName(n);}}) –

関連する問題