Java8ストリームでのforEachとforEachOrdered


86

これらのメソッドは実行順序が異なることを理解していますが、すべてのテストで異なる順序の実行を実現することはできません。

例:

System.out.println("forEach Demo");
Stream.of("AAA","BBB","CCC").forEach(s->System.out.println("Output:"+s));
System.out.println("forEachOrdered Demo");
Stream.of("AAA","BBB","CCC").forEachOrdered(s->System.out.println("Output:"+s));

出力:

forEach Demo
Output:AAA
Output:BBB
Output:CCC
forEachOrdered Demo
Output:AAA
Output:BBB
Output:CCC

2つの方法で異なる出力が生成される場合の例を提供してください。


多分並列ストリームで試してみてください。
pshemo 2015

@Pshemoそれは唯一の可能なオプションですか?
gstackoverflow 2015

5
不特定の順序は、「異なる順序であることが保証されている」ことを意味するものではありません。これは単に不特定を意味し、常に遭遇順序に一致する可能性を意味します。シャッフル機能は内蔵していません。
ホルガー2015

回答:


89
Stream.of("AAA","BBB","CCC").parallel().forEach(s->System.out.println("Output:"+s));
Stream.of("AAA","BBB","CCC").parallel().forEachOrdered(s->System.out.println("Output:"+s));

2行目は常に出力されます

Output:AAA
Output:BBB
Output:CCC

一方、最初のものは注文が保持されないため保証されません。forEachOrderedストリームがシーケンシャルであるかパラレルであるかに関係なく、ソースで指定された順序でストリームの要素を処理します。

forEachJavadocからの引用:

この操作の動作は明らかに非決定的です。並列ストリームパイプラインの場合、並列処理の利点が犠牲になるため、この操作はストリームの遭遇順序を尊重することを保証しません。

forEachOrderedJavadocが次のように述べている場合(私の強調):

ストリームにエンカウンター順序が定義されている場合は、ストリームのエンカウンター順序で、このストリームの各要素に対してアクションを実行します。


6
はい、その通りです。parallelStreamsでのみ可能ですか?
gstackoverflow 2015

6
現在、並列ストリームにのみ適用される場合でも(適用されるとは言いませんが)、順序付けられていないストリームを利用するためにいくつかの中間ステップが最適化されると、将来的に破損する可能性があります。ストリームは順序付けられていません。
the8472 2015

1
したがってforEachOrderedparallel?と一緒に使用するのは意味がありません。
ブーシャン2017年

3
@BhushanPatilはい、その通りです。stackoverflow.com/questions/47336825/…–
Sagar

1
forEachOrderedを使用すると、要素が順番に処理され、並列ストリームを使用すると、並列処理の利点が失われます。提案してください。
Deepak 2018年

30

forEach短く、ルックスはきれいに、私が使用することをお勧めしたいforEachOrderedための事項は、これを明示的に指定する場所すべての場所で。シーケンシャルストリームの場合、forEachは順序を尊重しているようであり、セマンティックに使用する必要があるストリームAPI内部コードの使用 forEach(シーケンシャルであることがわかっているストリームの場合)ですらありますforEachOrdered。それでも、後でストリームを並列に変更することを決定すると、コードが壊れます。またforEachOrdered、コードのリーダーを使用すると、「順序はここで重要です」というメッセージが表示されます。したがって、コードをより適切に文書化できます。

並列ストリームのforEach場合、非決定論的な順序で実行されるだけでなく、異なる要素の異なるスレッドで同時に実行されることもあります(これはでは不可能ですforEachOrdered)。

最後に、forEach/の両方forEachOrderedが役立つことはめったにありません。ほとんどの場合、あなたは実際にこれのような操作、いくつかの結果だけでなく、副作用を生成する必要があるreduceかをcollectより適切にする必要があります。を介して自然還元操作を表現することforEachは、通常、悪いスタイルと見なされます。


7
「最後に、forEach / forEachOrderedの両方が役立つことはめったにありません」。私はこれ以上同意できませんでした。これらの方法は使いすぎのようです。
ツナキ2015

ご回答ありがとうございます。しかし、それは実際の例ではありません。私はちょうど
java8を

forEachOrderedそのコードで使用することが意味的に必要なのはなぜですか?
RealSkeptic 2015

1
@RealSkeptic、それはユーザー指定のストリームです(に渡されますflatMap)。順序付けできるため、結果のストリームに同じ順序で配置する必要があります。
Tagir Valeev 2015

2
@RealSkeptic、あなたは本当の懐疑論者です!Stream.of("a", "b", "c").flatMap(s -> Stream.of("1", "2", "3").map(s::concat)).spliterator().hasCharacteristics(Spliterator.ORDERED)trueを返すため、結果のストリームの順序を決定する必要があります。JDKのドキュメントにこれについて明示的に記載する必要があると思われる場合は、バグを送信してください。
Tagir Valeev 2015

15

forEach()メソッドは、このストリームの各要素に対してアクションを実行します。並列ストリームの場合、この操作はストリームの順序を維持することを保証しません。

forEachOrdered() メソッドは、このストリームの各要素に対してアクションを実行し、定義された遭遇順序を持つストリームの各要素が遭遇順序で処理されることを保証します。

以下の例を見てください。

    String str = "sushil mittal";
    System.out.println("****forEach without using parallel****");
    str.chars().forEach(s -> System.out.print((char) s));
    System.out.println("\n****forEach with using parallel****");

    str.chars().parallel().forEach(s -> System.out.print((char) s));
    System.out.println("\n****forEachOrdered with using parallel****");

    str.chars().parallel().forEachOrdered(s -> System.out.print((char) s));

出力:

****forEach without using parallel****

sushil mittal

****forEach with using parallel****

mihul issltat

****forEachOrdered with using parallel****

sushil mittal
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.