web-dev-qa-db-ja.com

Java 8ストリームのforEachとforEachOrdered

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

例:

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つの方法で異なる出力が生成される場合の例を提供してください。

65
gstackoverflow
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は、ストリームがシーケンシャルかパラレルかに関係なく、ソースで指定された順序でストリームの要素を処理します。

forEach Javadocからの引用:

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

forEachOrdered Javadocの状態(エンファシス鉱山)の場合:

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

72
Tunaki

forEachは短く、きれいに見えますが、順序が重要なすべての場所でforEachOrderedを使用して、これを明示的に指定することをお勧めします。シーケンシャルストリームの場合、forEachは順序を尊重しているようで、APIの内部コード usesforEach(シーケンシャルであることがわかっているストリーム) forEachOrdered!を使用するにはそれでも、後でストリームをパラレルに変更すると、コードが破損する可能性があります。また、forEachOrderedを使用すると、コードのリーダーに「順序が重要です」というメッセージが表示されます。したがって、コードのドキュメント化が改善されます。

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

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

27
Tagir Valeev

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 ****

スシル・ミッタル

****並列を使用したforEach ****

ミフル・イスルタット

**** forEachOrdered with parallel ****

スシル・ミッタル

10
Sushil Mittal