恕我直言你可能真的不会java第5篇:Stream的状态与并行操作
一、回顾Stream管道流操作

通过前面章节的学习,我们应该明白了Stream管道流的基本操作。我们来回顾一下:
- 源操作:可以将数组、集合类、行文本文件转换成管道流Stream进行数据处理
- 中间操作:对Stream流中的数据进行处理,比如:过滤、数据转换等等
- 终端操作:作用就是将Stream管道流转换为其他的数据类型。这部分我们还没有讲,我们后面章节再介绍。
看下面的脑图,可以有更清晰的理解:

二、中间操作:有状态与无状态
其实在程序员编程中,经常会接触到“有状态”,“无状态”,绝大部分的人都比较蒙。而且在不同的场景下,“状态”这个词的含义似乎有所不同。但是“万变不离其宗”,理解“状态”这个词在编程领域的含义,笔者教给大家几个关键点:
- 状态通常代表公用数据,有状态就是有“公用数据”
- 因为有公用的数据,状态通常需要额外的存储。
- 状态通常被多人、多用户、多线程、多次操作,这就涉及到状态的管理及变更操作。
是不是更蒙了?举个例子,你就明白了
- web开发session就是一种状态,访问者的多次请求关联同一个session,这个session需要存储到内存或者redis。多次请求使用同一个公用的session,这个session就是状态数据。
- vue的vuex的store就是一种状态,首先它是多组件公用的,其次是不同的组件都可以修改它,最后它需要独立于组件单独存储。所以store就是一种状态。
回到我们的Stream管道流
- filter与map操作,不需要管道流的前面后面元素相关,所以不需要额外的记录元素之间的关系。输入一个元素,获得一个结果。
- sorted是排序操作、distinct是去重操作。像这种操作都是和别的元素相关的操作,我自己无法完成整体操作。就像班级点名就是无状态的,喊到你你就答到就可以了。如果是班级同学按大小个排序,那就不是你自己的事了,你得和周围的同学比一下身高并记住,你记住的这个身高比较结果就是一种“状态”。所以这种操作就是有状态操作。
三、Limit与Skip管道数据截取
List<String> limitN = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
.limit(2)
.collect(Collectors.toList());
List<String> skipN = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
.skip(2)
.collect(Collectors.toList());
- limt方法传入一个整数n,用于截取管道中的前n个元素。经过管道处理之后的数据是:[Monkey, Lion]。
- skip方法与limit方法的使用相反,用于跳过前n个元素,截取从n到末尾的元素。经过管道处理之后的数据是: [Giraffe, Lemur]
四、Distinct元素去重
我们还可以使用distinct方法对管道中的元素去重,涉及到去重就一定涉及到元素之间的比较,distinct方法时调用Object的equals方法进行对象的比较的,如果你有自己的比较规则,可以重写equals方法。
List<String> uniqueAnimals = Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
.distinct()
.collect(Collectors.toList());
上面代码去重之后的结果是: ["Monkey", "Lion", "Giraffe", "Lemur"]
五、Sorted排序
默认的情况下,sorted是按照字母的自然顺序进行排序。如下代码的排序结果是:[Giraffe, Lemur, Lion, Monkey],字数按顺序G在L前面,L在M前面。第一位无法区分顺序,就比较第二位字母。
List<String> alphabeticOrder = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
.sorted()
.collect(Collectors.toList());
排序我们后面还会给大家详细的讲一讲,所以这里暂时只做一个了解。
六、串行、并行与顺序
通常情况下,有状态和无状态操作不需要我们去关心。除非?:你使用了并行操作。
还是用班级按身高排队为例:班级有一个人负责排序,这个排序结果最后就会是正确的。那如果有2个、3个人负责按大小个排队呢?最后可能就乱套了。一个人只能保证自己排序的人的顺序,他无法保证其他人的排队顺序。
- 串行的好处是可以保证顺序,但是通常情况下处理速度慢一些
- 并行的好处是对于元素的处理速度快一些(通常情况下),但是顺序无法保证。这可能会导致进行一些有状态操作的时候,最后得到的不是你想要的结果。

Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
.parallel()
.forEach(System.out::println);
- parallel()函数表示对管道中的元素进行并行处理,而不是串行处理。但是这样就有可能导致管道流中后面的元素先处理,前面的元素后处理,也就是元素的顺序无法保证。
如果数据量比较小的情况下,不太能观察到,数据量大的话,就能观察到数据顺序是无法保证的。
Monkey
Lion
Lemur
Giraffe
Lion
通常情况下,parallel()能够很好的利用CPU的多核处理器,达到更好的执行效率和性能,建议使用。但是有些特殊的情况下,parallel并不适合:深入了解请看这篇文章:
https://blog.oio.de/2016/01/22/parallel-stream-processing-in-java-8-performance-of-sequential-vs-parallel-stream-processing/
该文章中几个观点,说明并行操作的适用场景:
- 数据源易拆分:从处理性能的角度,parallel()更适合处理ArrayList,而不是LinkedList。因为ArrayList从数据结构上讲是基于数组的,可以根据索引很容易的拆分为多个。

- 适用于无状态操作:每个元素的计算都不得依赖或影响任何其他元素的计算,的运算场景。
- 基础数据源无变化:从文本文件里面边读边处理的场景,不适合parallel()并行处理。parallel()一开始就容量固定的集合,这样能够平均的拆分、同步处理。
欢迎关注我的博客,里面有很多精品合集
- 本文转载注明出处(必须带连接,不能只转文字):字母哥博客。
觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力! 。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。
- 《手摸手教你学Spring Boot2.0》
- 《Spring Security-JWT-OAuth2一本通》
- 《实战前后端分离RBAC权限管理系统》
- 《实战SpringCloud微服务从青铜到王者》
- 《VUE深入浅出系列》
恕我直言你可能真的不会java第5篇:Stream的状态与并行操作的更多相关文章
- 恕我直言你可能真的不会java第11篇-Stream API终端操作
一.Java Stream管道数据处理操作 在本号之前写过的文章中,曾经给大家介绍过 Java Stream管道流是用于简化集合类元素处理的java API.在使用的过程中分为三个阶段.在开始本文之前 ...
- 恕我直言你可能真的不会java第9篇-Stream元素的匹配与查找
在我们对数组或者集合类进行操作的时候,经常会遇到这样的需求,比如: 是否包含某一个"匹配规则"的元素 是否所有的元素都符合某一个"匹配规则" 是否所有元素都不符 ...
- 恕我直言你可能真的不会java第6篇:Stream性能差?不要人云亦云
一.粉丝的反馈 问:stream比for循环慢5倍,用这个是为了啥? 答:互联网是一个新闻泛滥的时代,三人成虎,以假乱真的事情时候发生.作为一个技术开发者,要自己去动手去做,不要人云亦云. 的确,这位 ...
- 恕我直言你可能真的不会java第1篇:lambda表达式会用了么?
本文配套教学视频:B站观看地址 在本号之前写过的一些文章中,笔者使用了lambda表达式语法,一些读者反映说代码看不懂.本以为java 13都已经出了,java 8中最重要特性lambda表达式大家应 ...
- 恕我直言你可能真的不会java第2篇:Java Stream API?
一.什么是Java Stream API? Java Stream函数式编程接口最初是在Java 8中引入的,并且与lambda一起成为Java开发的里程碑式的功能特性,它极大的方便了开放人员处理集合 ...
- 恕我直言你可能真的不会java第4篇:Stream管道流Map操作
一.回顾Stream管道流map的基础用法 最简单的需求:将集合中的每一个字符串,全部转换成大写! List<String> alpha = Arrays.asList("Mon ...
- 恕我直言你可能真的不会java第7篇:像使用SQL一样排序集合
在开始之前,我先卖个关子提一个问题:我们现在有一个Employee员工类. @Data @AllArgsConstructor public class Employee { private Inte ...
- 恕我直言你可能真的不会java第8篇-函数式接口
一.函数式接口是什么? 所谓的函数式接口,实际上就是接口里面只能有一个抽象方法的接口.我们上一节用到的Comparator接口就是一个典型的函数式接口,它只有一个抽象方法compare. 只有一个抽象 ...
- 恕我直言你可能真的不会java第12篇-如何使用Stream API对Map类型元素排序
在这篇文章中,您将学习如何使用Java对Map进行排序.前几日有位朋友面试遇到了这个问题,看似很简单的问题,但是如果不仔细研究一下也是很容易让人懵圈的面试题.所以我决定写这样一篇文章.在Java中,有 ...
- 恕我直言你可能真的不会java第3篇:Stream的Filter与谓词逻辑
一.基础代码准备 建立一个实体类,该实体类有五个属性.下面的代码使用了lombok的注解Data.AllArgsConstructor,这样我们就不用写get.set方法和全参构造函数了.lombok ...
随机推荐
- 小工具之apk黑屏自动检测
在打包测试的时候经常发送给测试组之后,发现已进入游戏就黑屏,这个就浪费了测试组的精力,如果要测试多款产品的话,就会因为黑屏问题做很多无用功,这是程序就需要在发给测试的时候自己先测试产品会不会黑屏.同样 ...
- Linux显示行号设置
linux显示行号设置 第一步,打开vim vi ~/.vimrc 第二步,在该文件中加入一行,命令如下: set nu # 显示行号 set nonu # 不显示行号 微信公众号:喵哥解说 公众号介 ...
- vue 使用 elementUI 和 antd 的细微差别
Checkbox a-checkbox 没有value属性,绑定用checked Collapse 使用折叠面板的时候,antd 的层级关系是 .ant-collapse >.ant-colla ...
- jchdl - GSL实例 - ComplementOne(一的补码)
https://mp.weixin.qq.com/s/zZTnDdbCUCRGGpgpfAZsYQ 一的补码指对二进制数的每一位分别求补(二进制运算下0,1互为补数),实际运算即为对每一位取反.最 ...
- rewrite和return的简单需求
Rewrite 需求作业 背景:现在我有一个网站,www.linux.com www.linux.com访问主页面 friend.linux.com访问交友页面 blog.linux.com访问博客页 ...
- ASP.NET通过EntityFramework CodeFirst创建数据库
Number1 新建一个项目 给新项目添加一个实体数据模型 选择第三个 这里我创建两个有关系的类,也就是有外键关系的数据库表 using System; using System.Collection ...
- java实现第五届蓝桥杯扑克序列
扑克序列 AA223344,一共4对扑克牌.请你把它们排成一行. 要求:两个A中间有1张牌,两个2之间有2张牌,两个3之间有3张牌,两个4之间有4张牌. 4A3A2432, 2342A3A4 请填写出 ...
- LB服务,软LB的服务能力(下)
[摘要] 现在常用的LB软件,主要是LVS和nginx.普通情况下,LVS主要负责四层负载均衡,nginx负责七层.当然,业界也有友商基于LVS做出了七层负载均衡.本篇主要讲一下LVS的工作模式及各种 ...
- 温故知新-多线程-深入刨析volatile关键词
文章目录 摘要 volatile的作用 volatile如何解决线程可见? CPU Cache CPU Cache & 主内存 缓存一致性协议 volatile如何解决指令重排序? volat ...
- git提交代码托管平台流程
首先先安装git git官网 ---- https://git-scm.com/ 下载好傻瓜式安装即可 安装好过后,再桌面任意空白区域右键,看到以下两个选项即为安装成功 一般都用第二个选项也就是 Gi ...