peek() 和 allMatch() 如何在 Java 8 Stream API 中协同工作

Bar*_*ona 9 java java-8 java-stream

我发现了一个关于 peek 方法的 Java 8 Stream API 的测验,如下所示

Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));
Run Code Online (Sandbox Code Playgroud)

输出是

Fred
Jim
Run Code Online (Sandbox Code Playgroud)

我很困惑这个流是如何工作的?我的预期结果应该是

Fred
Jim
Sheila
Run Code Online (Sandbox Code Playgroud)

peek() 方法是一个中间操作,它处理 Stream 中的每个元素。谁能给我解释一下。

ern*_*t_k 9

这是一种称为短路的流优化。本质上,发生的事情是allMatch防止在流上执行不必要的中间操作,因为在知道最终结果时执行这些操作毫无意义。

就好像这发生了:

take"Fred"
peek("Fred")
evaluate("Fred".startsWith("F"))
decide whether the result of allMatch() is known for sure: Not yet

take"Jim"
peek("Jim")
evaluate("Jim".startsWith("F"))
decide whether the result of allMatch() is known for sure: Yes
Run Code Online (Sandbox Code Playgroud)

"Jim".startsWith("F")被评估时,结果allMatch(s -> s.startsWith("F"))是肯定已知的。在 之后管道中出现什么值并不重要"Jim",我们知道所有以“F”开头的值都是假的

这不是特定于peek/allMatch组合,有多个中间和终端短路操作。java.util.stream包的文档状态:

此外,一些操作被视为短路操作。如果中间操作在呈现无限输入时可能因此产生有限流,则它是短路的。如果终端操作在无限输入时可能在有限时间内终止,则它是短路的。在管道中进行短路操作是无限流处理在有限时间内正常终止的必要条件,但不是充分条件。

将此扩展到有限流,并且短路操作避免了不必要的管道步骤的执行,就像您的示例一样。