Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Stream.sorted().forEach() work as intended? [duplicate]

While working on a Java project, I came across code that looked like this:

someMap.keySet().stream().sorted().forEach(/* ... */);

The intention here is clearly to do something for each key in the map, according to the keys' natural order, and this does seem to be what happens in practice. However, I'm not sure if this behavior is guaranteed. The Javadoc for Stream#forEach says:

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. For any given element, the action may be performed at whatever time and in whatever thread the library chooses.

I know that if the code were using .parallelStream() instead of .stream() that it wouldn't be guaranteed to work, but since it is using a sequential stream (which the Javadoc doesn't say anything about), I'm not sure. Is this guaranteed to always work, or would that code need to be using .forEachOrdered() instead of .forEach() for it to be?

EDIT: I believe that this question is not a duplicate of forEach vs forEachOrdered in Java 8 Stream, because that question is asking "what's an example of a difference between forEach and forEachOrdered in general", and the accepted answer is basically "parallel streams". This question is specifically about sequential streams.

like image 362
Joseph Sible-Reinstate Monica Avatar asked Dec 07 '22 16:12

Joseph Sible-Reinstate Monica


2 Answers

It's not guaranteed that the forEach terminal operation will process elements in the encounter order hence the "is explicitly nondeterministic". Although under the current implementation it should process the elements of a sequential stream in the encounter order of the stream.

forEachOrdered is primarily for cases where you're using a parallel stream and want to respect the encounter order of the stream if the stream has a defined encounter order.

Using forEach or forEachOrdered on a sequential stream will have the same effect so it's a matter of preference.

As mentioned above, under the current implementation we know that the forEach terminal operation should process the elements of a sequential stream in the encounter order of the stream but since it's not stated in the java doc it's better to sit on the fence and use forEachOrdered if you really care about the iteration order.

like image 119
Ousmane D. Avatar answered Dec 22 '22 00:12

Ousmane D.


Under the current implementation it is - but the documentation is pretty clear not to specify this as a rule. This obviously can change, but at the moment it does not, even when doing:

Stream.of(5, 4, 3, 1)
      .unordered()
      .forEach(System.out::println);

Even if you are breaking the order on purpose, for sequential streams, data is not shuffled on purpose internally - at least not at the moment.

You have to be careful though, not to rely on it as things can change between versions, here is one example

like image 32
Eugene Avatar answered Dec 22 '22 00:12

Eugene