Java 8和Java 9中的Stream.peek()方法


73

我正在学习Java 8 lambda表达式,并且想问一下下面的Java代码,这些代码与peek我遇到的函数接口中的方法有关。

在IDE上执行程序时,它不提供任何输出。我期望它会给2, 4, 6

import java.util.Arrays;
import java.util.List;

public class Test_Q3 {

    public Test_Q3() {
    }

    public static void main(String[] args) {
        List<Integer> values = Arrays.asList(1, 2, 3);
        values.stream()
              .map(n -> n * 2)
              .peek(System.out::print)
              .count();
    }
}

4
也许应将java-8标记替换为java-9
Eran

9
添加了Java-9。我认为应该两者兼有,因为这是关于两者之间的差异。
eis

9
java8java9之间学习有很大的区别。概括这个问题的标题...另一方面,Holger在这个答案中几乎涵盖了这个问题
Naman

Answers:


66

我假设您正在Java 9下运行此程序?您无需更改SIZED流的属性,因此无需执行mappeek全部。

换句话说,您关心的只是count最终结果,但与此同时,您不得List任何方式(filter例如通过或distinct)这是在Streams中完成的优化。

顺便说一句,即使您添加了虚拟过滤器,它也会显示您期望的结果:

values.stream ()
      .map(n -> n*2)
      .peek(System.out::print)
      .filter(x -> true)
      .count();

19
…现在想象一个将来的版本,该版本能够分析aPredicate的代码以预先预测其结果,即对于特定的流管道,它是永远不会实现还是永远不会实现……
Holger

4
因此,道德是,不要将其count用作强制执行流以产生副作用的方法。
puhlen

27
@puhlen不,道德是,请勿将其peek用作强制执行流以产生副作用(调试除外)的方法。如果要对每个流元素应用操作,请使用forEach
Holger

@Holger但是,如果要执行操作并使用a从流中获取过滤的结果,该collect()怎么办?如果要在单个链中执行此操作,没有其他方法可以窥视。
klaar

2
正如已经说过的,@ klaar:“试图使现有代码适合单个Java流调用链”是一个人为的目标。甚至重写代码以使用流也不是一个有用的目标,特别是当此重写甚至不产生干净的代码时。如前所述,您也不需要peek,因为以后对结果集合执行检查时没有区别。特别是,因为这样的后续测试可以引发这些检查的异常,这与不同peek
Holger

65

这是Stream接口的Javadoc中的一些相关引号:

在优化结果的计算时,流实现具有很大的自由度。例如,如果流实现可以证明不会影响计算结果,则可以从流管道中取消操作(或整个阶段)-因此可以取消行为参数的调用。这意味着行为参数的副作用可能并不总是被执行,并且不应该被依赖,除非另有说明(例如通过终端操作forEach和forEachOrdered)。(有关这种优化的具体示例,请参见count()操作上记录的API注释。有关更多详细信息,请参见流包文档的副作用部分。)

更具体地说,来自Javadoc的count()方法:

API注意:

如果实现能够直接从流源计算计数,则实现可以选择不执行流管道(顺序地或并行地)。在这种情况下,将不会遍历任何源元素,也不会评估任何中间操作。强烈建议避免带有副作用的行为参数,除了无害情况(例如调试)外。例如,考虑以下流:

List<String> l = Arrays.asList("A", "B", "C", "D");
long count = l.stream().peek(System.out::println).count();

流源所覆盖的元素数量(即List)是已知的,并且中间操作peek不会注入或删除流中的元素(对于flatMap或filter操作可能就是这种情况)。因此,计数就是List的大小,不需要执行管道,并且副作用是打印出list元素。

这些引号仅出现在Java 9的Javadoc上,因此它必须是新的优化。


8
值得一提的是count()的javadoc在Java 8中也没有说相同
。– eis

6
Stream.peek->的文档中开始,在流实现能够优化某些或所有元素的产生的情况下(例如使用短路操作findFirst,例如或在中描述的示例中count),将不会调用该操作对于那些元素。
纳曼

4
@nullpointer也仅存在于Java 9文档中,尽管它总是被暗示。
Holger
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.