The Javadoc for Stream.forEach
says (emphasis mine):
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. If the action accesses shared state, it is responsible for providing the required synchronization.
The same text is present in the Java 9 Early Access Javadoc.
The first sentence ("explicitly nondeterministic") suggests (but doesn't explicitly say) that encounter order is not preserved by this method. But the next sentence, that explicitly says order is not preserved, is conditioned on "For parallel stream pipelines", and that condition would be unnecessary if the sentence applied regardless of parallelism. That leaves me unsure whether forEach preserves encounter order for sequential streams.
This answer points out a spot where the streams library implementation calls .sequential().forEach(downstream)
. That suggests forEach is intended to preserve order for sequential streams, but could also just be a bug in the library.
I've sidestepped this ambiguity in my own code by using forEachOrdered
to be on the safe side, but today I discovered that NetBeans IDE's "use functional operations" editor hint will convert
for (Foo foo : collection)
foo.bar();
into
collection.stream().forEach((foo) -> {
foo.bar();
});
which introduces a bug if forEach does not preserve encounter order. Before I report a bug against NetBeans, I want to know what the library actually guarantees, backed up by a source.
I'm looking for an answer drawing from authoritative sources. That could be an explicit comment in the library implementation, discussion on the Java development mailing lists (Google didn't find anything for me but maybe I don't know the magic words), or a statement from the library designers (of which I know two, Brian Goetz and Stuart Marks, are active on Stack Overflow). (Please do not answer with "just use forEachOrdered instead" -- I already do, but I want to know if code that doesn't is wrong.)