Java 8 Stream 原理 - 调试笔记
2017-05-19 17:33
363 查看
Java 8 Stream 原理——调试笔记
理解的前提:对流的执行步骤有基本认识——中间操作和终止操作
示例程序:
Stream<String> stream = Stream.of(
"a", "bdd", "bdd" );
stream.filter( s -> s.length() > 1 )//
.sorted()//
.mapToInt( String::length )//
.sum();
代码解析:
1) stream.filter(xx); // 对应的是ReferencePipeline
类,创建一个新的流,将当前流赋值给新的流 previousStage 字段,并返回新创建的流。
代码:
return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE ...
2) sorted()、mapToInt()
方法都类似。
3) xx.sum() 对应的是IntPipeline
类
4) 代码产生流的链结构是:
sum() = mapToInt(pre) -> sorted(pre) -> filter(pre) -> stream
由于流只有调用终止操作才会真正执行,所以在 .sum()
打断点,开始调试。。。
断点调试:
xx.sum(); // F5 进入 sum() 方法
reduce(0, Integer::sum); // F5 进入
ReduceOps.makeInt(identity, op) // 产生一个终止符
TerminalOp
evaluate(ReduceOps.makeInt(identity, op)); // F5, F7, F5 进入到 AbstractPipeline 类
sourceSpliterator(terminalOp.getOpFlags()) // 创建一个
spliterator (暂叫分叉器)
terminalOp.evaluateSequential(this, sourceSpliterator(terminalOp.getOpFlags())); // F5, F7, F5, F7, F5
进入到 ReduceOps
类
helper.wrapAndCopyInto(makeSink(), spliterator).get();
// 1) F5, F7, F5 进入 AbstractPipeline.wrapAndCopyInto(S, Spliterator<P_IN>)
// 2) F5, F7, F5 进入 wrapSink(Sink<E_OUT>) //
此方法返回一个调用链为 filter() -> sorted() -> mapToInt()
收集点(sink)
// 3) F7, F5 进入 copyInto(Sink<P_IN>, Spliterator<P_IN>)
// 3a) wrappedSink.begin(spliterator.getExactSizeIfKnown());
算是真正开始执行流式操作
// 4) F5 spliterator.forEachRemaining(wrappedSink)
进入 Spliterators$ArraySpliterator
类,此方法是对集合元素进行迭代。
action 对应的是 filter(),
再看 ReferencePipeline.filter(xx)
源码
public void accept(P_OUT u) {
if (predicate.test(u)) // 测试通过
downstream.accept(u); // 下一个流处理
}
下一个流对应的是 sorted()
跟踪 ReferencePipeline.sorted() -> SortedOps.makeRef(this) -> new OfRef<>(upstream)
其 comparator
是一个默认的比较器:Comparator.naturalOrder()
SortedOps$OfRef.opWrapSink(int flags, Sink<T> sink)
方法创建 RefSortingSink 对象。
具体看 RefSortingSink,
也可以在 spliterator.forEachRemaining(wrappedSink)
里的
do { action.accept((T)a[i]); } while (++i < hi);
一直 F5, F7
也能找到
RefSortingSink 的工作方式很简单:accept(T t)
只是添加元素;end()
方法才排序,然后 for
循环调用 downstream.accept(t),最后调用
downstream.end();
其中 RefSortingSink.end() 是在 AbstractPipeline.copyInto(Sink<P_IN>, Spliterator<P_IN>)
里调用的(代码:wrappedSink.end();)
下一个流对应的是 mapToInt()
查看 ReferencePipeline.mapToInt(xx),很简单——将值转换成
int 然后传给
downstream
最后sum() 调用的是 TerminalOp.get(),里面的
state 是
operator.applyAsInt(state, t)
累加的
算法的理解:
final <P_IN> Sink<P_IN>
wrapSink(Sink<E_OUT> sink) {
Objects.requireNonNull(sink);
for ( @SuppressWarnings("rawtypes")
AbstractPipeline p=AbstractPipeline.this; p.depth > 0; p=p.previousStage) {
sink = p.opWrapSink(p.previousStage.combinedFlags, sink);
}
return (Sink<P_IN>) sink;
}
sum() = mapToInt(pre) -> sorted(pre) -> filter(pre) -> stream
sum(none) -> map(prev) -> sort()
sink = sum(none).opWrapSink(none)
sink = sum(sink) // this = sum
sink = map(sum(sink)) // map = sum.prev, sink = sum(sink)
sink = sort(map(sum(sink))) // sort = map.prev, sink = map(sum(sink))
灵感来了一下就能理解,灵感没来纠结了半天也不能理解,能用画图理解更好.
教训:super(upstream,
opFlags); 没再跟进去,导致字段理解有误!!!
理解的前提:对流的执行步骤有基本认识——中间操作和终止操作
示例程序:
Stream<String> stream = Stream.of(
"a", "bdd", "bdd" );
stream.filter( s -> s.length() > 1 )//
.sorted()//
.mapToInt( String::length )//
.sum();
代码解析:
1) stream.filter(xx); // 对应的是ReferencePipeline
类,创建一个新的流,将当前流赋值给新的流 previousStage 字段,并返回新创建的流。
代码:
return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE ...
2) sorted()、mapToInt()
方法都类似。
3) xx.sum() 对应的是IntPipeline
类
4) 代码产生流的链结构是:
sum() = mapToInt(pre) -> sorted(pre) -> filter(pre) -> stream
由于流只有调用终止操作才会真正执行,所以在 .sum()
打断点,开始调试。。。
断点调试:
xx.sum(); // F5 进入 sum() 方法
reduce(0, Integer::sum); // F5 进入
ReduceOps.makeInt(identity, op) // 产生一个终止符
TerminalOp
evaluate(ReduceOps.makeInt(identity, op)); // F5, F7, F5 进入到 AbstractPipeline 类
sourceSpliterator(terminalOp.getOpFlags()) // 创建一个
spliterator (暂叫分叉器)
terminalOp.evaluateSequential(this, sourceSpliterator(terminalOp.getOpFlags())); // F5, F7, F5, F7, F5
进入到 ReduceOps
类
helper.wrapAndCopyInto(makeSink(), spliterator).get();
// 1) F5, F7, F5 进入 AbstractPipeline.wrapAndCopyInto(S, Spliterator<P_IN>)
// 2) F5, F7, F5 进入 wrapSink(Sink<E_OUT>) //
此方法返回一个调用链为 filter() -> sorted() -> mapToInt()
收集点(sink)
// 3) F7, F5 进入 copyInto(Sink<P_IN>, Spliterator<P_IN>)
// 3a) wrappedSink.begin(spliterator.getExactSizeIfKnown());
算是真正开始执行流式操作
// 4) F5 spliterator.forEachRemaining(wrappedSink)
进入 Spliterators$ArraySpliterator
类,此方法是对集合元素进行迭代。
action 对应的是 filter(),
再看 ReferencePipeline.filter(xx)
源码
public void accept(P_OUT u) {
if (predicate.test(u)) // 测试通过
downstream.accept(u); // 下一个流处理
}
下一个流对应的是 sorted()
跟踪 ReferencePipeline.sorted() -> SortedOps.makeRef(this) -> new OfRef<>(upstream)
其 comparator
是一个默认的比较器:Comparator.naturalOrder()
SortedOps$OfRef.opWrapSink(int flags, Sink<T> sink)
方法创建 RefSortingSink 对象。
具体看 RefSortingSink,
也可以在 spliterator.forEachRemaining(wrappedSink)
里的
do { action.accept((T)a[i]); } while (++i < hi);
一直 F5, F7
也能找到
RefSortingSink 的工作方式很简单:accept(T t)
只是添加元素;end()
方法才排序,然后 for
循环调用 downstream.accept(t),最后调用
downstream.end();
其中 RefSortingSink.end() 是在 AbstractPipeline.copyInto(Sink<P_IN>, Spliterator<P_IN>)
里调用的(代码:wrappedSink.end();)
下一个流对应的是 mapToInt()
查看 ReferencePipeline.mapToInt(xx),很简单——将值转换成
int 然后传给
downstream
最后sum() 调用的是 TerminalOp.get(),里面的
state 是
operator.applyAsInt(state, t)
累加的
算法的理解:
final <P_IN> Sink<P_IN>
wrapSink(Sink<E_OUT> sink) {
Objects.requireNonNull(sink);
for ( @SuppressWarnings("rawtypes")
AbstractPipeline p=AbstractPipeline.this; p.depth > 0; p=p.previousStage) {
sink = p.opWrapSink(p.previousStage.combinedFlags, sink);
}
return (Sink<P_IN>) sink;
}
sum() = mapToInt(pre) -> sorted(pre) -> filter(pre) -> stream
sum(none) -> map(prev) -> sort()
sink = sum(none).opWrapSink(none)
sink = sum(sink) // this = sum
sink = map(sum(sink)) // map = sum.prev, sink = sum(sink)
sink = sort(map(sum(sink))) // sort = map.prev, sink = map(sum(sink))
灵感来了一下就能理解,灵感没来纠结了半天也不能理解,能用画图理解更好.
教训:super(upstream,
opFlags); 没再跟进去,导致字段理解有误!!!
相关文章推荐
- Java笔记分享-CrazyChao(Java重点及补充 序列化 Transient 远程调试 GC原理)
- Java学习笔记--Lesson1(Java跨平台原理的剖析和Java环境变量的配置
- Java多核线程笔记-volatile的原理与技巧
- jdk的配置和JVM内部原理 java 基础学习笔记 第一天
- Java 学习笔记21:Java断点调试的使用
- Android的调试原理--学习笔记
- Java入门笔记7_Stream
- 《黑马程序员》java笔记->基本数据类型包装类及自动拆箱装箱原理,数组排序练习字符串切割
- Java多核线程笔记-volatile的原理与技巧
- Java多核线程笔记-volatile的原理与技巧
- Java多核线程笔记-volatile的原理与技巧
- JAVA学习笔记之二控件消息原理
- Android的调试原理--学习笔记
- Java多核线程笔记-volatile的原理与技巧
- Java多核线程笔记-volatile的原理与技巧
- Java入门笔记 7 Stream
- java学习笔记---第11章异常与调试
- Java笔记——Class.getResourceAsStream和ClassLoader.getResourceAsStream
- JAVA 笔记 ClassLoader.getResourceAsStream() 与 Class.getResourceAsStream()的区别
- Java学习笔记之垃圾收集机制和原理