forEach vs forEachOrdered in Java 8 Stream
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
gstackoverflow
Updated on January 17, 2021Comments
-
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 over 8 yearsYes, you are right. Is it possible only for parallelStreams ?
-
Tunaki over 8 years"Finally both forEach/forEachOrdered are rarely useful". I could not agree more. It seems these methods are over-used.
-
RealSkeptic over 8 yearsWhy is it semantically necessary to use
forEachOrdered
in that code? -
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 over 8 yearsWhy? 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 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(Spliterator.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 over 8 yearsEven 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 almost 7 yearsSo it makes no sense to use
forEachOrdered
withparallel
? -
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 ofstream.forEach(list::add)
? But what aboutstream.forEach(this::doSomethingTotallyUnrelatedToFillingAList)
? -
Sagar over 6 years@BhushanPatil Yes, that's correct. stackoverflow.com/questions/47336825/…
-
Deepak almost 6 yearsUsing forEachOrdered will process element by order then using parallel streams will loose benefits of parallelism. Please suggest.
-
cbaldan over 5 yearsI 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.