1. 概要

このチュートリアルでは、StreamからListを取得するためのさまざまなメソッドを見ていきます。 また、それらの違いと、いつどの方法を使用するかについても説明します。

2. ストリーム要素をリストに収集する

StreamからListを取得することは、Streamパイプラインで最もよく使用されるターミナル操作です。 Java 16より前は、 Stream.collect()メソッドを呼び出し、それを引数としてCollectorに渡して要素を収集していました。 Collector 自体は、 Collectors.toList()メソッドを呼び出すことによって作成されました。

ただし、Streamインスタンスから直接Listを取得するメソッドに対する変更要求があります。 Java 16のリリース後、Stream上で直接新しいメソッドであるtoList()を呼び出して、Listを取得できるようになりました。 StreamEx のようなライブラリは、Streamから直接Listを取得する便利な方法も提供します。

次を使用して、Stream要素をListに蓄積できます。

  • Stream.collect(Collectors.toList()):Java8以降
  • Stream.collect(Collectors.toUnmodizableList()):Java10以降
  • Stream.toList():Java16以降

リリースの時系列順にメソッドを使用します。

3. リストの分析

まず、前のセクションで説明した方法からリストを作成しましょう。 その後、それらの特性を分析しましょう。

すべての例で、次のStreamの国コードを使用します。

Stream.of(Locale.getISOCountries());

3.1. リストの作成

次に、さまざまな方法を使用して、国コードの指定されたStreamからListを作成します。

まず、 Collectors:toList()を使用してListを作成しましょう。

List<String> result = Stream.of(Locale.getISOCountries()).collect(Collectors.toList());

その後、 Collectors.toUnmodizableList()を使用して収集しましょう。

List<String> result = Stream.of(Locale.getISOCountries()).collect(Collectors.toUnmodifiableList());

ここで、これらのメソッドでは、 Collector インターフェイスを介してストリームリストに蓄積します。これにより、追加の割り当てとコピーが行われます。 Streamを直接操作することはありません。

次に、 Stream.toList()を使用してコレクションを繰り返します。

List<String> result = Stream.of(Locale.getISOCountries()).toList();

ここでは、リストストリームから直接取得するため、余分な割り当てやコピーを防ぐことができます。

したがって、 toList() Stream で直接使用すると、他の2つの呼び出しと比較して、より簡潔で、きちんとしていて、便利で、最適です。

3.2. 蓄積されたリストの調査

作成したリストのタイプを調べることから始めましょう。

Collectors.toList()は、Stream要素をArrayListに収集します。

java.util.ArrayList

Collectors.toUnmodizableList()は、Stream要素を変更不可能なListに収集します。

java.util.ImmutableCollections.ListN

Stream.toList()は、要素を変更不可能なListに収集します。

java.util.ImmutableCollections.ListN

Collectors.toList()の現在の実装では、可変の List が作成されますが、メソッドの仕様自体は、[のタイプ、可変性、直列化可能性、またはスレッドセーフを保証しません。 X222X]リスト。

一方、 Collectors.toUnmodizableList() Stream.toList()、はどちらも、変更不可能なリストを生成します。

これは、 Collectors.toList()、の要素に対して追加や並べ替えなどの操作を実行できるが、 Collectors.toUnmodizableList()およびStreamの要素に対しては実行できないことを意味します。 toList()。 

3.3. リストでのヌル要素の許可

Stream.toList()は変更不可能な List を生成しますが、それでも Collectors.toUnmodizableList()。と同じではありません。これはStreamのためです。 toList() null 要素を許可し、 Collectors.toUnmodizableList()null要素を許可しません。 ただし、 Collectors.toList()では、null要素を使用できます。

Collectors.toList()は、null要素を含むStreamが収集されたときに、Exceptionをスローしません。

Assertions.assertDoesNotThrow(() -> {
    Stream.of(null,null).collect(Collectors.toList());
});

Collectors.toUnmodizableList()は、null要素を含むStreamを収集すると、NulPointerExceptionをスローします。

Assertions.assertThrows(NullPointerException.class, () -> {
    Stream.of(null,null).collect(Collectors.toUnmodifiableList());
});

Stream.toList()は、null要素を含むStreamを収集しようとしたときに、NulPointerExceptionをスローしません。

Assertions.assertDoesNotThrow(() -> {
    Stream.of(null,null).toList();
});

したがって、これは、コードをJava8からJava10またはJava16に移行するときに注意する必要があります。 Collectors.toList()または Collectors.toUnmodizableList()。の代わりに Stream.toList()を盲目的に使用することはできません。

3.4. 分析の要約

次の表は、分析から得られたリストの相違点と類似点をまとめたものです。

4. 異なるtoList()メソッドを使用する場合

Stream.toList()を追加する主な目的は、 CollectorAPIの冗長性を減らすことです。

前に示したように、Listを取得するためにC ollectorsメソッドを使用することは非常に冗長です。 一方、 Stream.toList()メソッドを使用すると、コードが簡潔になります。

それでも、前のセクションで見たように、 Stream.toList() Collectors.toList()または Collectors.toUnmodizableList()へのショートカットとして使用することはできません。 ]。

次に、 Stream.toList()は、の実装がコレクターインターフェイスから独立しているため、使用するメモリが少なくなります。 Stream要素をListに直接蓄積します。 したがって、ストリームのサイズが事前にわかっている場合は、 Stream.toList()。を使用するのが最適です。

第3に、 Stream APIは、 toList()メソッドの実装のみを提供することがわかっています。 マップまたはセットを取得するための同様のメソッドは含まれていません。 したがって、リスト、マップ、セットなどのコンバーターを取得するための統一されたアプローチが必要な場合は、引き続き CollectorAPIを使用します。 これにより、一貫性が維持され、混乱が回避されます。

最後に、Java 16より前のバージョンを使用している場合は、引き続きCollectorsメソッドを使用する必要があります。

次の表は、特定のメソッドの最適な使用法をまとめたものです。

5. 結論

この記事では、StreamからListを取得する最も一般的な3つの方法を分析しました。 次に、主な相違点と類似点を確認しました。 また、これらの方法をいつどのように使用するかについても説明しました。

いつものように、この記事で使用されている例のソースコードは、GitHubから入手できます。