不変コレクションへのJavaストリームを集める

1前書き

この簡単な記事では、標準のコレクターは可変データ構造でのみ機能するため、特別なアプローチを必要とする、不変のコレクションにJavaのストリームを集めるさまざまな方法について説明します。

2 Mavenの依存関係

GoogleのGuavaライブラリを使用して、いくつかの例を示します。

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>22.0</version>
</dependency>

この依存関係の最新バージョンはhttps://search.maven.org/classic/#search%7C1%7Cg%3A%22com.google.guava%22%20AND%20a%3A%22guava%22から入手できます。[ここに]。

3 Javaの collectingAndThen() を使う

Javaの Collectors クラスの collectingAndThen()メソッドは、 Collector 、および Collectorから返される結果に適用される finisher Function を受け入れます。

@Test
public void whenUsingCollectingToImmutableList__thenSuccess() {
    List<String> givenList = Arrays.asList("a", "b", "c");
    List<String> 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グアバの Collectors を使う

Guava 21以降、すべての不変クラスには、標準の Collectorsと同じくらい簡単に使用できる Collector__が付属しています。

@Test
public void whenCollectToImmutableList__thenSuccess() {
    List<Integer> list = IntStream.range(0, 9)
      .boxed()
      .collect(ImmutableList.toImmutableList());
}

結果のインスタンスは RegularImmutableList です。

class com.google.common.collect.RegularImmutableList

5カスタムコレクターの構築

それでは、さらに一歩進めて、カスタムの Collector を実装しましょう。

この目的を達成するために、静的な Collector.of() メソッドを使用します。

public static <T> Collector<T, List<T>, List<T>> toImmutableList() {
    return Collector.of(ArrayList::new, List::add,
    (left, right) -> {
      left.addAll(right);
      return left;
    }, Collections::unmodifiableList);
}

カスタム Collectors の実装についてもっと学ぶために、 この記事 のセクション4を見てください。以上です。

上記のメソッドはカスタムクラスの一部です

他の組み込み Collectors と同じように使用できます。

@Test
public void whenCollectToMyImmutableListCollector__thenSuccess() {
    List<String> givenList = Arrays.asList("a", "b", "c", "d");
    List<String> result = givenList.stream()
      .collect(MyImmutableListCollector.toImmutableList());
}

最後に、出力を確認しましょう。

class java.util.Collections$UnmodifiableRandomAccessList

5.1. MyImmutableListCollector ジェネリック を作る

私たちの実装には1つの制限があります - それは ArrayList によって支えられた不変のインスタンスを常に返します。ただし、わずかな改善で、このコレクターにユーザー指定のタイプを返させることができます。

public static <T, A extends List<T>> Collector<T, A, List<T>> toImmutableList(
  Supplier<A> supplier) {

    return Collector.of(
      supplier,
      List::add, (left, right) -> {
        left.addAll(right);
        return left;
      }, Collections::unmodifiableList);
}

メソッド実装で 仕入先を決定する代わりに、ユーザから 仕入先を要求しています。

@Test
public void whenPassingSupplier__thenSuccess() {
    List<String> givenList = Arrays.asList("a", "b", "c", "d");
    List<String> result = givenList.stream()
      .collect(MyImmutableListCollector.toImmutableList(LinkedList::new));
}

ArrayList の代わりに LinkedList を使用していることに注意してください。これを実行して結果を確認しましょう。

class java.util.Collections$UnmodifiableList

今回は、 UnmodifiableRandomAccessList ではなく UnmodifiableList を取得しました。

6. 結論

この短い記事では、 Stream を集めて不変の Collection にするさまざまな方法を説明しました。

この記事の完全なソースコードをチェックアウトしてください。