Java8 Stream 的核心秘密
创始人
2024-02-04 15:30:50

小伙伴们好呀,我是 4ye,今天来分享下 Java8 Stream 的源码

核心回顾

  1. stream 是一次性的,不是数据结构,不存储数据,不改变源数据.。
  2. API 分为终端和中间操作,中间操作是惰性的,碰到终端才去执行。
  3. 中间操作有无状态和有状态之分,有状态需要更改上一步操作获得的所有元素,才可以进行下一步操作,比如 排序 sorted,去重 distinct,跳过 skip,限制 limit 这四个,需要多迭代一次。
  4. 终端操作有短路与否之分,短路操作有 anyMatch, allMatch, noneMatch, findFirst, findAny

整体概览

这里列出一些重要的类,是看源码过程中必须了解的。

比如 :

  • Sink 接口是数据实际操作的地方,核心方法: begin,accept,end
  • AbstractPipeline 抽象类是核心的数据结构,双链表

demo代码

这里沿用上文的例子

        Student aStud = new Student(1, "a");Student bStud = new Student(2, "b");Student cStud = new Student(3, null);
​
//         集合的创建 一List collect1 = Stream.of(aStud, bStud, cStud).collect(Collectors.toList());collect1.forEach(System.out::println);
​List studNameList = studentList.stream().map(Student::getName).filter(Objects::nonNull).map(String::toUpperCase).sorted().map(e -> e + "c").collect(Collectors.toList());
复制代码

步骤解析

都在这里了 👇

这里步骤太多了,就不一一放出来了 ,列下核心

  1. wrapSink, 创建 Sink 链,将管道的 Sink 操作连接在一起
  2. copyInto , 处理数据

wrapSink()

开始套娃,从 ReducingSink 往前套

opWarpSink 方法调用的是每一步 中间操作 中的方法

通过 单链表 的形式将他们联系在一起

Sink 链创建结果

copyInto()

这里判断是不是 短路操作 ,然后就去执行 Sink 的 begin,accept,end 方法。

通过 forEachRemaining 进行内部迭代,这个是 Spliterator 的方法。

map 链节点,直接调用传进来的方法,

filter 链节点,多一步判断

sorted 节点,添加到 list 中。

注意,此时没有继续调用 downstream.accept 方法!

意味着,我们代码中的 5 个中间步骤只执行了前 3 个。

不过别担心, sorted 链节点中它重写了这个 end,并开启对新数据的新一轮遍历

这就是我们提到的,有状态中间操作多一次迭代的原因

最后呢,是来到终止操作 TerminalOp 中的 accept,这里执行的是 list 的 add 方法(我们调用 Collectors.toList() 中构建的),至此,数据添加到 state 中

获取数据,ReducingSink 继承了 Box 这个抽象类,最后 get 方法得到结果。

总结

代码对应的执行流程👇

  1. 先创建流,出现了 Head 节点

  2. 创建中间管道 Pipeline

  3. 调用终端操作后有三步 👇

    (一)将中间管道的 Sink 操作连接在一起 (wrapSink) (二)处理数据 (copyInto),主要调用 Sink 中的 begin,accept(核心),end 操作 (三)返回结果,ReducingSink 中的 get 方法

主要记住这个 wrapSink 方法 和 copyInto 方法。

一个套娃,一个调用 begin,accept,end 等方法。

那么,这个 stream 的原理机制就出来了:

利用 wrapSink 方法将各个中间操作中的 Sink 嵌套在一起,然后来到 copyInto 方法,调用 begin 通知各个 Sink 做好准备,接着进行内部迭代调用 accept 方法,再调用 end 方法完成数据的操作,最后通过 get 方法,获取新容器中的数据,便是结果了。

此外,源码的 链式调用API 写法设计模式 的使用以及 泛型四大函数式接口 组合构建的高度抽象,封装写法,对我们的编码能力,源码阅读能力也有很大的帮助!

比如 这个 Consumer+Function 接口的组合,配合泛型上下限的使用

源码中 访问者模式工厂模式 等设计模式的影子

访问者模式: 将数据结构与数据操作分离

对应源码:数据结构是 Pipeline ,操作是 Sink

对 stream 的特点更加熟悉

比如:

  1. stream 是一次性的,不是数据结构,不存储数据,不改变源数据.。
  2. 中间操作是惰性的,遇到 终端操作才真正执行
  3. 有状态的中间操作的特殊之处在于多迭代一次
  4. 内部迭代
  5. 终端操作主要做了两件事,串连中间操作,调用 accept 方法处理数据

当然这里我也只测试了 非短路模式,短路模式又是怎样设计的呢,小伙伴们可以自己上手 debug 下,加深印象。

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...