Java8和Java9中的Stream.peek()方法

Java8和Java9中的Stream.peek()方法,java,lambda,java-8,java-9,peek,Java,Lambda,Java 8,Java 9,Peek,我正在学习Java8Lambda表达式,并想询问以下与我遇到的函数接口中的方法相关的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<In

我正在学习Java8Lambda表达式,并想询问以下与我遇到的函数接口中的方法相关的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();
    }
}
导入java.util.array;
导入java.util.List;
公开课考试第三季{
公共测试_Q3(){
}
公共静态void main(字符串[]args){
列表值=数组.asList(1,2,3);
values.stream()
.map(n->n*2)
.peek(系统输出::打印)
.count();
}
}

我想您是在Java 9下运行的?您没有更改流的
size
属性,因此根本不需要执行
map
peek

换句话说,您所关心的只是将
计数
作为最终结果,但同时您不会以任何方式(例如通过
过滤器
不同的
)更改
列表的初始大小。这是在流中进行的优化

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

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

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

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

更具体地说,从方法的Javadoc:

API注释:

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

List<String> l = Arrays.asList("A", "B", "C", "D");
long count = l.stream().peek(System.out::println).count();
listl=Arrays.asList(“A”、“B”、“C”、“D”);
long count=l.stream().peek(System.out::println.count();
流源(列表)所覆盖的元素数量是已知的,中间操作peek不会向流中注入元素或从流中移除元素(可能是flatMap或filter操作的情况)。因此,计数是列表的大小,不需要执行管道,并且作为副作用,打印列表元素


这些引号只出现在Java 9的Javadoc上,因此它一定是一个新的优化。

值得注意的是,在Java 8中也不这么说。从-->的文档中可以看出,流实现能够优化掉部分或所有元素的生产(例如短路操作,如
findFirst
,或在
count
中描述的示例中),将不会为这些元素调用该操作。@nullpointer这也仅在Java 9文档中存在,尽管它总是隐含的。也许Java-8标记应该替换为Java-9added Java-9。我认为它应该是两者兼而有之,因为这是关于两者之间的区别。和之间的区别很好。概括t的标题他的问题……另一方面,霍尔格在……中几乎涵盖了这一点。现在想象一下,未来的版本能够分析
谓词
的代码,提前预测其结果,也就是说,对于特定的流管道,它是否永远不会或总是实现……因此,寓意是,不要使用
计数
作为一种方法o强制流执行以产生副作用。@puhlen不,寓意是,不要使用
peek
作为强制流执行以产生副作用的方法(调试除外)。如果要对每个流元素应用操作,请使用
forEach
@klaar“在单个链中执行”这不是一个实际的目标。当你先收集到一个列表中,然后通过该结果列表上的
forEach
执行你的操作时,你不会注意到有什么不同。此外,当这个问答已经证明为什么peek根本不是一个替代品时,说“peek没有替代品”是没有意义的。@klaar如前所述,“尝试将现有代码放入java流调用的单个链中”是一个人为的目标。即使重写代码以使用流也不是一个有用的目标,尤其是当这种重写甚至不能生成干净的代码时。正如所说的,无论如何,您不需要
peek
,因为它在之后对结果集执行检查时没有任何区别。特别是,这样的后续测试可以抛出ese检查异常,不同于
peek