Java Stream:forEach 和 forEachOrdered 之间的区别

Lui*_*ese 3 java foreach java-8 java-stream

前提:我已经阅读了这个问题和其他问题,但我需要一些澄清。

我知道该Stream.forEach方法在处理并行流时(不仅)有所不同,这解释了为什么

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

印刷

one two three four five six
Run Code Online (Sandbox Code Playgroud)

但是当涉及到中间操作时,当流并行化时,顺序就不再保证了。所以这段代码

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

会打印类似的东西

four six five one three two 
Run Code Online (Sandbox Code Playgroud)

说该forEachOrdered方法仅影响其自身执行中的元素顺序是否正确?直觉上,我认为//1示例与

//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));
Run Code Online (Sandbox Code Playgroud)

难道是我的直觉错了?我是否遗漏了整个机制的某些内容?

Hol*_*ger 5

您是对的,为 的行为做出的保证forEachOrdered仅适用于该行为,而不适用于其他行为。但\xe2\x80\x99 假设这与 相同是错误的.sequential().forEach(\xe2\x80\xa6)

\n\n

sequential会将整个流管道转换为顺序模式,因此,传递给的操作forEach将由同一线程执行,而且还会执行前面的peek\xe2\x80\x99s 操作。parallel对于大多数中间操作,或的确切位置sequential是无关的,并且指定两者没有意义,因为只有最后一个操作是相关的。

\n\n

forEach此外,即使在当前实现中没有\xe2\x80\x99t任何后果,仍然无法保证使用时的顺序。这在\xe2\x80\x9c 中进行了讨论。Stream.forEach 是否尊重顺序流的遇到顺序?\xe2\x80\x9d

\n\n

状态的Stream.forEachOrdered文档:

\n\n
\n

此操作一次处理一个元素,如果存在,则按遇到顺序处理。对一个元素执行操作发生在对后续元素执行操作之前,但对于任何给定元素,该操作可以在库选择的任何线程中执行。

\n
\n\n

因此,该操作可能会被不同的线程调用,Thread.currentThread()但不能同时运行。\n此外,如果流具有遇到顺序,它将在此处重新构建。这个答案揭示了遭遇顺序处理顺序的区别。

\n