stream 中的foreEach()调用分析
2019-07-20 本文已影响0人
pengyuyancode
Stream.java对于forEach方法的解释:
为该流的每个元素执行一个操作。该方法是一个终止操作;对于并行流来说,遍历顺序可能是不准确的。对于共享变量的操作,需要提供额外的同步机制。
/**
* Performs an action for each element of this stream.
*
* <p>This is a <a href="package-summary.html#StreamOps">terminal
* operation</a>.
*
* <p>The behavior of this operation is explicitly nondeterministic.
* For parallel stream pipelines, this operation does <em>not</em>
* guarantee to respect the encounter order of the stream, as doing so
* would sacrifice the benefit of parallelism. For any given element, the
* action may be performed at whatever time and in whatever thread the
* library chooses. If the action accesses shared state, it is
* responsible for providing the required synchronization.
*
* @param action a <a href="package-summary.html#NonInterference">
* non-interfering</a> action to perform on the elements
*/
void forEach(Consumer<? super T> action);
该方法有俩个实现
第一个位于 ReferencePipeline.java 中
@Override
public void forEach(Consumer<? super P_OUT> action) {
evaluate(ForEachOps.makeRef(action, false));
}
第二个位于Head 中,它是ReferencePipeline.java 中的一个内部类
static class Head<E_IN, E_OUT> extends ReferencePipeline<E_IN, E_OUT> {
........
// Optimized sequential terminal operations for the head of the pipeline
@Override
public void forEach(Consumer<? super E_OUT> action) {
if (!isParallel()) {
sourceStageSpliterator().forEachRemaining(action);
}
else {
super.forEach(action);
}
}
.......
}
现在有俩端代码
List<Integer> list= Arrays.asList(2,3,4,5,6);
list.stream().forEach(System.out::println);
List<Integer> list= Arrays.asList(2,3,4,5,6);
list.stream().map(item->item).forEach(System.out::println);
对于第一段代码stream.forEach(System.out::println)
,它会调用Head中的forEach()
对于第二段代码stream().map(item->item).forEach(System.out::println)
他会调用ReferencePipeline 中的forEach()
。
原因:java8中对于Stream操作分为几个阶段:流源,中间操作,终止操作。
list.stream().forEach(System.out::println);
:流源+终止操作。而Head中的foreach()方法对于流源遍历做了优化。
stream().map(item->item).forEach(System.out::println)
:map()操作是一个中间操作。对于有中间操作的流来说forEach()需要关注每个中间操作都做了什么,所以调用的是ReferencePipeline 中的forEach()