Stream.peek() 方法在 Java 8 与 Java 9

2022-08-31 13:30:14

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

在 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();
    }
}

答案 1

我假设你是在Java 9下运行的吗?您不会更改流的属性,因此无需执行或根本不执行。SIZEDmappeek

换句话说,你所关心的只是最终结果,但与此同时,你不会以任何方式改变的初始大小(例如通过或),这是在Streams中完成的优化。countListfilterdistinct

顺便说一句,即使您添加了虚拟过滤器,这也将显示您期望的内容:

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

答案 2

以下是来自Javadoc of Stream接口的一些相关引用:

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

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

接口说明:

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

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

流源(List)覆盖的元素数是已知的,中间操作(peek)不会注入流中或从中删除元素(如 flatMap 或筛选器操作)。因此,计数是 List 的大小,并且不需要执行管道,并且作为副作用,打印出列表元素。

这些引号只出现在Java 9的Javadoc上,所以它必须是一个新的优化。


推荐