Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Stream: difference between forEach and forEachOrdered

Premise: I've already read this question and others, but I need some clarifications.

I understand that Stream.forEach method makes the difference (not only) when dealing with parallel streams, and this explains why this

//1
Stream.of("one ","two ","three ","four ","five ","six ")
.parallel()
.forEachOrdered(item -> System.out.print(item));

prints

one two three four five six

But when it comes to intermediate operations, the order is not guaranteed anymore when stream is parallelized. So this code

//2
Stream.of("one ","two ","three ","four ","five ","six ")
.parallel()
.peek(item -> System.out.print(item))
.forEachOrdered(item -> System.out.print(""));

will print something like

four six five one three two 

Is it correct to say that forEachOrdered method only affects order of elements in its own execution? Intuitively, I'm thinking of //1 example being exactly the same as

//3
Stream.of("one ","two ","three ","four ","five ","six ")
.parallel()
.peek(item -> System.out.print("")) //or any other intermediate operation
.sequential()
.forEach(item -> System.out.print(item));

Is my intuition wrong? Am I missing something about the whole mechanism?

like image 594
Luigi Cortese Avatar asked Aug 30 '26 21:08

Luigi Cortese


1 Answers

You are right in that the guarantees made for the action of forEachOrdered only apply to that action and nothing else. But it’s wrong to assume that this is the same as .sequential().forEach(…).

sequential will turn the entire stream pipeline into sequential mode, thus, the action passed to forEach will be executed by the same thread, but also the preceding peek’s action. For most intermediate operations, the exact placement of parallel or sequential is irrelevant and specifying both makes no sense as only the last one will be relevant.

Also, there is still no guaranty made about the ordering when using forEach, even if it hasn’t any consequences in the current implementation. This is discussed in “Does Stream.forEach respect the encounter order of sequential streams?”

The documentation of Stream.forEachOrdered states:

This operation processes the elements one at a time, in encounter order if one exists. Performing the action for one element happens-before performing the action for subsequent elements, but for any given element, the action may be performed in whatever thread the library chooses.

So the action may get invoked by different threads, as perceivable by Thread.currentThread() but not run concurrently. Further, if the stream has an encounter order, it will get reconstituted at this place. This answer sheds some light one the difference of encounter order and processing order.

like image 197
Holger Avatar answered Sep 01 '26 09:09

Holger