public static void main(String[] args) throws Exception {
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
// below code does not work
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
System.out.println("1:test:" + s);
return true;
}
}).map(s -> {
System.out.println("1:map:" + s);
return s;
});
// below code works
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
System.out.println("2:test" + s);
return true;
}
}).map(s -> {
System.out.println("2:map" + s);
return s;
}).collect(Collectors.toList());
}
上述代码的输出为:
2:test1
2:map1
2:test2
2:map2
2:test3
2:map3
2:test4
2:map4
我不知道为什么第一次不起作用。
只有在执行lambda时才会调用lambdap -> doSomething(p)
中的doSomething
。该语句的简单存在并不保证执行,而普通(而不是lambda(语句doSomething(x)
保证执行。
map
和filter
是中间操作,而collect
是终端操作。对于每一个中间操作,都会返回一个新的流对象(Stream
的任何实现,如StatelessOp
、StatefulOp
或流的基元专用化(如IntStream
、LongStream
等((,它存储任何信息,如您的情况下的映射或过滤函数。这里没有实际执行。
流评估是在调用evaluate
方法时进行的。现在,如果您看到任何终端操作,它都会调用这个evaluate
方法。这是您作为参数传递给中间操作的lambda应用于流元素的情况。这就是为什么流被认为是惰性评估的原因->评估仅从应用终端操作开始。
因此,您的第一个代码块不起作用,因为没有终端操作,并且您传递的lambda也没有执行。但在第二个代码块中,您调用了一个终端操作,并对流进行了评估。还要注意,不需要针对每个流元素执行中间操作->参考
您可以在ReferencePipeline
中看到每个流方法的实现。
流管道由一个源(可能是一个数组集合、生成器函数、I/O通道等(,零或更多中间操作(将一个流转换为另一个流,例如filter(Predicate((和终端操作(产生结果或副作用,如count((或forEach(Consumer((。流懒惰;只有当终端操作启动,并且仅消耗源元素根据需要。
点击此处阅读更多