peek()和allMatch()如何在Java 8 Stream API中一起工作


10

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

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

输出是

Fred
Jim

我对此流的工作方式感到困惑吗?我的预期结果应该是

Fred
Jim
Sheila

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

Answers:


10

这是流优化,称为短路。本质上,发生的事情是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

"Jim".startsWith("F")被评估时,结果allMatch(s -> s.startsWith("F"))肯定是已知的。紧随其后的管道中的值无关紧要"Jim",我们知道所有以“ F”开头的值都是false

这并非特定于peek/ allMatch组合,存在多个中间和端子短路操作。java.util.stream包的文档状态:

此外,某些操作被认为是短路操作。如果出现无限输入时中间操作可能会产生有限的流,则该中间操作会短路。如果出现无限输入时,端子操作可能会在有限时间内终止,则该端子操作会发生短路。在管道中进行短路操作是使无限流的处理在有限时间内正常终止的必要条件,但不是充分条件。

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


5
Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));
  • 第一次通过,Fred被打印。如此匹配
  • 第二次至Jim打印。它不匹配,所以allMatch终止,因为“所有不匹配”
  • 因此,没有从流中消耗掉最后一个项目。

3

文档peek方法,比方说(重点煤矿):

返回由该流的元素组成的流,并在从结果流中消耗元素时对每个元素另外执行提供的操作。

所以在这种情况下,peek看不到,"Sheila"因为该值没有从流中消耗。一经"Jim"消耗,.allMatch(s -> s.startsWith("F"))就知道的结果是false,因此无需消耗流中的更多元素。


1

根据JavaDoc of allMatch():

返回此流的所有元素是否与提供的谓词匹配。如果不需要确定结果,则可能无法对所有元素都评估谓词。如果流为空,则返回{@code true},并且不评估该谓词。

@apiNote

此方法评估流元素上谓词的通用量化(对于所有x P(x))。如果流是空的,则称该定量是空虚的,并且始终为{@code true}(与P(x)无关)。

谓词应用于此流的元素@return {@code true},如果该流的所有元素都与提供的谓词匹配或该流为空,否则为{@code false}

在您的情况下:

1-

p(x) : s -> s.startsWith("F")

X : "Fred"

result : X P(X) = true

2

p(x) : s -> s.startsWith("F")

X : "Jim"

result : X P(X) = false

因为XP(X)= false,所以不会进行进一步评估

boolean result = Arrays.asList("Fred", "Finda", "Fish")
            .stream()
            .peek(System.out::println)
            .allMatch(s -> s.startsWith("F"));
    System.out.println("Result "+result);

输出为:

Fred
Finda
Fish
Result true

此处流已完全处理,因为每个元素的xP(x)= true

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.