在 Java8和 Java9中使用 Stream.Peak()方法

我正在通过 Java8 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();
}
}
7922 次浏览

我猜你用的是 Java 9吧?您没有改变流的 SIZED属性,因此根本不需要执行 mappeek

换句话说,所有你关心的是 count作为最终结果,但同时你不改变 List的初始大小在 任何的方式(通过 filter例如或 distinct)这是一个优化完成的流。

顺便说一下,即使你添加了一个虚拟过滤器,它也会显示你所期望的:

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

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

流实现在优化结果的计算方面允许有很大的余地。例如,流实现可以自由地省略流管道中的操作(或整个阶段)——因此省略行为参数的调用——如果它能证明它不会影响计算结果的话。这意味着不应该依赖于 行为参数的副作用可能并不总是被执行,除非另有说明(例如终端操作 forEach 和 forEachOrded)。(有关这种优化的特定示例,请参见 count ()操作中记录的 API 说明。有关更多细节,请参见流程包文档的副作用部分。)

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

注:

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

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

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

这些引号只出现在 Java9的 Javadoc 中,因此它必须是一个新的优化。