.stream()
を使用すると、 や のようなチェーン操作を使用して並列ストリームを使用できることは理解しています.filter()
。 しかし、小さな操作 (たとえば、リストの要素を印刷する) を実行する必要がある場合、それらの違いは何ですか?
collection.stream().forEach(System.out::println);
collection.forEach(System.out::println);
ベストアンサー1
図のような単純なケースでは、ほとんど同じです。ただし、重要な微妙な違いがいくつかあります。
1 つの問題は順序付けに関するものです。 ではStream.forEach
、順序は未定義です。 順次ストリームでは発生しそうにありませんが、 がStream.forEach
任意の順序で実行されることは の仕様の範囲内です。 これは並列ストリームでは頻繁に発生します。 対照的に、 は、が指定されている場合Iterable.forEach
、常に の反復順序で実行されますIterable
。
もう一つの問題は副作用です。 で指定されたアクションは非干渉でStream.forEach
ある必要があります。(java.util.stream パッケージのドキュメント) はIterable.forEach
潜在的に制約が少ないです。 のコレクションについてはjava.util
、Iterable.forEach
は通常そのコレクションの を使用しますIterator
。そのほとんどは、失敗を早くするそして、反復中にコレクションの構造が変更されると例外が発生しますConcurrentModificationException
。ただし、反復中に構造的ではない変更は許可されます。たとえば、ArrayList クラスのドキュメントは、「要素の値を設定するだけでは構造の変更にはなりません」と述べています。したがって、 for アクションは問題なくArrayList.forEach
基になる値を設定できます。ArrayList
並行コレクションはまたもや異なります。フェイルファストではなく、弱い一貫性完全な定義は、そのリンクにあります。ただし、簡単に について考えてみましょう。そのメソッドConcurrentLinkedDeque
に渡されるアクションは、基礎となる deque を構造的に変更することができ、スローされることはありません。ただし、発生する変更は、この反復処理で表示される場合と表示されない場合があります。(したがって、「弱い」一貫性です。)forEach
ConcurrentModificationException
同期コレクションを反復処理する場合、さらに別の違いが見られますIterable.forEach
。このようなコレクションでは、Iterable.forEach
コレクションのロックを取得する一度だけ実行し、アクション メソッドのすべての呼び出しにわたって保持します。Stream.forEach
呼び出しでは、ロックしないコレクションのスプリッテレータを使用します。これは、非干渉の一般的なルールに依存します。ストリームをサポートするコレクションは、反復処理中に変更される可能性があり、変更された場合、またはConcurrentModificationException
一貫性のない動作が発生する可能性があります。