forEach vs forEachOrdered in Java 8 Stream

64,666

Solution 1

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));

The second line will always output

Output:AAA
Output:BBB
Output:CCC

whereas the first one is not guaranted since the order is not kept. forEachOrdered will processes the elements of the stream in the order specified by its source, regardless of whether the stream is sequential or parallel.

Quoting from forEach Javadoc:

The behavior of this operation is explicitly nondeterministic. For parallel stream pipelines, this operation does not guarantee to respect the encounter order of the stream, as doing so would sacrifice the benefit of parallelism.

When the forEachOrdered Javadoc states (emphasis mine):

Performs an action for each element of this stream, in the encounter order of the stream if the stream has a defined encounter order.

Solution 2

Although forEach shorter and looks prettier, I'd suggest to use forEachOrdered in every place where order matters to explicitly specify this. For sequential streams the forEach seems to respect the order and even stream API internal code uses forEach (for stream which is known to be sequential) where it's semantically necessary to use forEachOrdered! Nevertheless you may later decide to change your stream to parallel and your code will be broken. Also when you use forEachOrdered the reader of your code sees the message: "the order matters here". Thus it documents your code better.

Note also that for parallel streams the forEach not only executed in non-determenistic order, but you can also have it executed simultaneously in different threads for different elements (which is not possible with forEachOrdered).

Finally both forEach/forEachOrdered are rarely useful. In most of the cases you actually need to produce some result, not just side-effect, thus operations like reduce or collect should be more suitable. Expressing reducing-by-nature operation via forEach is usually considered as a bad style.

Solution 3

forEach() method performs an action for each element of this stream. For parallel stream, this operation does not guarantee to maintain order of the stream.

forEachOrdered() method performs an action for each element of this stream, guaranteeing that each element is processed in encounter order for streams that have a defined encounter order.

take the example below:

    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));

Output:

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

sushil mittal

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

mihul issltat

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

sushil mittal
Share:
64,666
gstackoverflow
Author by

gstackoverflow

Updated on January 17, 2021

Comments

  • gstackoverflow
    gstackoverflow over 3 years

    I understand that these methods differ the order of execution but in all my test I cannot achieve different order execution.

    Example:

    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));
    

    Output:

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

    Please provide examples when 2 methods will produce different outputs.

  • gstackoverflow
    gstackoverflow over 8 years
    Yes, you are right. Is it possible only for parallelStreams ?
  • Tunaki
    Tunaki over 8 years
    "Finally both forEach/forEachOrdered are rarely useful". I could not agree more. It seems these methods are over-used.
  • RealSkeptic
    RealSkeptic over 8 years
    Why is it semantically necessary to use forEachOrdered in that code?
  • Tagir Valeev
    Tagir Valeev over 8 years
    @RealSkeptic, it's user-specified stream (passed into flatMap). It can be ordered, so it must be placed into the resulting stream in the same order.
  • RealSkeptic
    RealSkeptic over 8 years
    Why? Where in the contract of flatMap did you see that it says that it will be placed in the output in the same order?
  • Tagir Valeev
    Tagir Valeev over 8 years
    @RealSkeptic, you are the real skeptic! Stream.of("a", "b", "c").flatMap(s -> Stream.of("1", "2", "3").map(s::concat)).spliterator().hasCharacteristics(Splite‌​rator.ORDERED) returns true, thus the order for the resulting stream must be determined. If you feel that JDK documentation should explicitly say about this, feel free to submit a bug.
  • the8472
    the8472 over 8 years
    Even if it only would apply to parallel streams right now - and I'm not saying it does - it still might break in the future if some intermediate steps get optimized to take advantage of unordered streams, e.g. a sort could use an unstable algorithm if the stream is unordered.
  • Bhushan
    Bhushan almost 7 years
    So it makes no sense to use forEachOrdered with parallel ?
  • Sxilderik
    Sxilderik over 6 years
    “forEach rarely useful”… As for filling a collection, I can see your point – but isn’t list.addAll(stream.collect(toList)) taking twice the memory of stream.forEach(list::add) ? But what about stream.forEach(this::doSomethingTotallyUnrelatedToFillingALi‌​st) ?
  • Sagar
    Sagar over 6 years
    @BhushanPatil Yes, that's correct. stackoverflow.com/questions/47336825/…
  • Deepak
    Deepak almost 6 years
    Using forEachOrdered will process element by order then using parallel streams will loose benefits of parallelism. Please suggest.
  • cbaldan
    cbaldan over 5 years
    I strongly disagree that forEach is rarely used. When you need to process large collections of data, you obviously will get the task done in parallel. It's quite useful to submit a lambda function there. And when I do need the results ordered, I use it with an IntStream; the processing method receives the input collection, the output will collection, along with the int from then stream, which is the index for both collections. This way, no thread safe data collection has to be used, which let's your code run faster, and due to the sync collections, order is still preserved.