学习笔记——Java Stream 源码学习

思路

先上一段代码

        List<User> userList = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            userList.add(new User(i, "wtq", "1234"));
        }
        userList.stream()
                .filter(user -> user.getUserId() > 3)
                .filter(user -> user.getUserId() > 4)
                .forEach(System.out::println);

Java的stream流, 平时很常用的功能, 让代码变的更简洁, 可读性也更好, 但是完全没有了解过它内部的逻辑. 今天有时间自己尝试梳理了一下源码, 这也算是我第一次独立分析源码, 写的不好还请见谅.

整体逻辑

先在前面总结一下整套流程的大体逻辑.
在学习stream的使用方法时, 就了解到一些流操作分为中间操作终止操作. 中间操作并不会触发逻辑执行, 真正触发操作执行是终止操作.
一段流操作中的中间操作在内部使用AbstractPipeline被连接成双向链表的结构, 并使用Sink保存具体的操作方式(如上面的过滤逻辑).
直到有一个中间操作对象调用了终止操作.终止操作需要实现TerminalOpSink . 由终止操作构造Sink调用单向链表. 最终将Sink执行链委托给Spliterator调用.
重要的类
AbstractPipeline : 双向链表元素类
Sink : 操作链, 串联整个流操作中的具体逻辑的类
Spliterator : 真正遍历调用操作链的类
在这里插入图片描述
在这里插入图片描述
这里暂时听不明白没关系, 下面正式进入代码

读代码

stream()

从第一个方法开始分析.
在这里插入图片描述
这个方法构造了最初的Stream对象, 第一个参数是通过调用内部方法获取的.先不管这个参数.
在这里插入图片描述
点进StreamSupport提供的方法, 可以发现这里的Stream对象的实际类型是ReferencePipeline的内部类Head构造了双向链表的头.

filter() 中间操作

注意, 这里filter()其实是由Head对象调用的, 注意搞清楚this的值.
这里创建了一个StatelessOp.
在这里插入图片描述
继续追溯构造方法, 实际是调用了AbstractPipeline的构造方法, 此时构造对象的previousStage就是Head. 同时为previousStagenextStage赋值. 这时候, 双向链表已经有了两个元素.
这里想象一下第二个filter运行时, 会将上一个filter的StatelessOp对象作为previousStage, 执行相同的操作. 做完这些操作, 双向链表里加入了第三个元素.
在这里插入图片描述

foreach() 终止操作

此时终止操作是由最后一个中间操作调用
这里将终止操作的逻辑保存在ForEachOps对象中
在这里插入图片描述
在这里插入图片描述
终止操作调用最终评估方法, 将全部中间操作构成的链表传入方法
在这里插入图片描述
继续传递
在这里插入图片描述
在这里插入图片描述构造Sink单向链表
在这里插入图片描述
Sink链表传递给Spliterator
在这里插入图片描述
为每个元素调用Sink操作链
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值