JavaのStream APIでtoListした結果を、独自のListにaddAllしていたソースがあったので、 Collectors#toCollection
でできるよ、と教える機会があった。
Collectors#collectingAndThen
に比べて知名度が低いようなのでメモ。
collectingAndThen
これは検索するとよく出てくる。
Collectors#collectingAndThen(Collector, Function)
で、追加の変換処理を実行できる。
また、Javadocに、サンプルとして不変リストへの変換方法が書いてある。
追加の仕上げ変換が実行されるようにCollectorを適応させます。たとえば次のように、常に不変リストが生成されるようにtoList()コレクタを適応させることができます。
List<String> people = people.stream().collect(collectingAndThen(toList(), Collections::unmodifiableList));
第1引数で渡したCollectorの結果を引数とするメソッドやコンストラクタがあれば、メソッド参照を使ってFunctionとして第2引数に指定できるため、GuavaのImmutable系クラスなども使用可能。
// Guavaの場合
List<String> people = people.stream()
.collect(collectingAndThen(toList(), ImmutableList::copyOf));
toCollection
こちらが今回の本命。
collectingAndThen
の第2引数に指定できるメソッドやコンストラクタがない場合でも、Collectionを実装していれば Collectors.toCollection(Supplier)
で、Supplierが返したCollection実装インスタンスにStreamの内容を追加できる。
デフォルトコンストラクタがあれば、第2引数は コレクション実装クラス::new
でいい。戻り値は、Supplierが返したインスタンスになる。
// オレオレリスト class MyList<T> extends ArrayList<T> { ... } MyList<String> myList = Stream.of("a", "b", "c") .collect(toCollection(MyList::new));
collectingAndThen
でも、任意のインスタンスを生成して Collection#addAll
するFunctionを記述すれば使えるが、こちらのほうがわかりやすいだろう。