Javaストリームを不変のコレクションに収集する
1. 前書き
この簡単な記事では、JavaStreamsを不変のCollections –に収集するさまざまな方法を見ていきます。これは、標準のCollectorsが可変のデータ構造でのみ機能するため、特別なアプローチが必要です。
2. メーベン依存
3. JavaのcollectingAndThen()を使用する
JavaのCollectorsクラスのcollectingAndThen()メソッドは、Collectorと、Collector:から返された結果に適用されるfinisherFunctionを受け入れます。
@Test
public void whenUsingCollectingToImmutableList_thenSuccess() {
List givenList = Arrays.asList("a", "b", "c");
List result = givenList.stream()
.collect(collectingAndThen(toList(), ImmutableList::copyOf));
System.out.println(result.getClass());
}
toCollection() Collectorを直接,で使用することはできないため、要素を一時リストに収集し、そこから不変のリストを作成する必要があります。
この例では、toList()コレクターを使用してStreamをListに変換してから、ImmutableListを作成しています。 ImmutableListはGuavaライブラリの一部です。 出力をコンソールに記録すると、基になるクラスのクラスが取得されます
出力をコンソールに記録すると、基になるList実装のクラスが取得されます。
class com.google.common.collect.RegularImmutableList
4. GuavaのCollectorsを使用する
Guava 21以降、すべての不変クラスには、標準のCollectors:と同じくらい簡単に使用できるCollectorが付属しています。
@Test
public void whenCollectToImmutableList_thenSuccess() {
List list = IntStream.range(0, 9)
.boxed()
.collect(ImmutableList.toImmutableList());
}
結果のインスタンスはRegularImmutableListです。
class com.google.common.collect.RegularImmutableList
5. カスタムコレクターの構築
それでは、さらに一歩進んで、カスタムCollectorを実装しましょう。 この目標を達成するために、静的なCollector.of()メソッドを使用します。
public static Collector, List> toImmutableList() {
return Collector.of(ArrayList::new, List::add,
(left, right) -> {
left.addAll(right);
return left;
}, Collections::unmodifiableList);
}
カスタムCollectorsの実装の詳細については、this articleのセクション4を参照してください。 以上です。 上記のメソッドはカスタムクラスの一部です
これで、他の組み込みCollectorsと同じように使用できます。
@Test
public void whenCollectToMyImmutableListCollector_thenSuccess() {
List givenList = Arrays.asList("a", "b", "c", "d");
List result = givenList.stream()
.collect(MyImmutableListCollector.toImmutableList());
}
最後に、出力を確認しましょう。
class java.util.Collections$UnmodifiableRandomAccessList
5.1. MyImmutableListCollectorをジェネリックにする
私たちの実装には1つの制限があります-それは常にArrayListで裏打ちされた不変のインスタンスを返します。 ただし、少し改善することで、このコレクターがユーザー指定の型を返すようにすることができます。
public static > Collector> toImmutableList(
Supplier supplier) {
return Collector.of(
supplier,
List::add, (left, right) -> {
left.addAll(right);
return left;
}, Collections::unmodifiableList);
}
ここで、メソッド実装でsupplierを決定する代わりに、ユーザーにsupplierを要求しています。
@Test
public void whenPassingSupplier_thenSuccess() {
List givenList = Arrays.asList("a", "b", "c", "d");
List result = givenList.stream()
.collect(MyImmutableListCollector.toImmutableList(LinkedList::new));
}
現在、ArrayListの代わりにLinkedListを使用していることに注意してください。 これを実行して結果を見てみましょう。
class java.util.Collections$UnmodifiableList
今回は、UnmodifiableRandomAccessListではなくUnmodifiableListを取得しました。
6. 結論
この短い記事では、Streamを不変のCollectionに収集するさまざまな方法を見てきました。
この記事over on GitHubの完全なソースコードを確認してください。