恕我直言你可能真的不会java第5篇:Stream的状态与并行操做

1、回顾Stream管道流操做


经过前面章节的学习,咱们应该明白了Stream管道流的基本操做。咱们来回顾一下:vue

  • 源操做:能够将数组、集合类、行文本文件转换成管道流Stream进行数据处理
  • 中间操做:对Stream流中的数据进行处理,好比:过滤、数据转换等等
  • 终端操做:做用就是将Stream管道流转换为其余的数据类型。这部分咱们尚未讲,咱们后面章节再介绍。

看下面的脑图,能够有更清晰的理解:java

2、中间操做:有状态与无状态

其实在程序员编程中,常常会接触到“有状态”,“无状态”,绝大部分的人都比较蒙。并且在不一样的场景下,“状态”这个词的含义彷佛有所不一样。可是“万变不离其宗”,理解“状态”这个词在编程领域的含义,笔者教给你们几个关键点:程序员

  • 状态一般表明公用数据,有状态就是有“公用数据”
  • 由于有公用的数据,状态一般须要额外的存储。
  • 状态一般被多人、多用户、多线程、屡次操做,这就涉及到状态的管理及变动操做。

是否是更蒙了?举个例子,你就明白了web

  • web开发session就是一种状态,访问者的屡次请求关联同一个session,这个session须要存储到内存或者redis。屡次请求使用同一个公用的session,这个session就是状态数据。
  • vue的vuex的store就是一种状态,首先它是多组件公用的,其次是不一样的组件均可以修改它,最后它须要独立于组件单独存储。因此store就是一种状态。

回到咱们的Stream管道流redis

  • filter与map操做,不须要管道流的前面后面元素相关,因此不须要额外的记录元素之间的关系。输入一个元素,得到一个结果。
  • sorted是排序操做、distinct是去重操做。像这种操做都是和别的元素相关的操做,我本身没法完成总体操做。就像班级点名就是无状态的,喊到你你就答到就能够了。若是是班级同窗按大小个排序,那就不是你本身的事了,你得和周围的同窗比一下身高并记住,你记住的这个身高比较结果就是一种“状态”。因此这种操做就是有状态操做。

3、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]

4、Distinct元素去重

咱们还可使用distinct方法对管道中的元素去重,涉及到去重就必定涉及到元素之间的比较,distinct方法时调用Object的equals方法进行对象的比较的,若是你有本身的比较规则,能够重写equals方法。spring

List<String> uniqueAnimals = Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
        .distinct()
        .collect(Collectors.toList());

上面代码去重以后的结果是: ["Monkey", "Lion", "Giraffe", "Lemur"]vuex

5、Sorted排序

默认的状况下,sorted是按照字母的天然顺序进行排序。以下代码的排序结果是:[Giraffe, Lemur, Lion, Monkey],字数按顺序G在L前面,L在M前面。第一位没法区分顺序,就比较第二位字母。编程

List<String> alphabeticOrder = Stream.of("Monkey", "Lion", "Giraffe", "Lemur")
        .sorted()
        .collect(Collectors.toList());

排序咱们后面还会给你们详细的讲一讲,因此这里暂时只作一个了解。后端

6、串行、并行与顺序

一般状况下,有状态和无状态操做不须要咱们去关心。除非?:你使用了并行操做。数组

仍是用班级按身高排队为例:班级有一我的负责排序,这个排序结果最后就会是正确的。那若是有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()一开始就容量固定的集合,这样可以平均的拆分、同步处理。

欢迎关注个人博客,里面有不少精品合集

  • 本文转载注明出处(必须带链接,不能只转文字):字母哥博客

以为对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创做动力! 。另外,笔者最近一段时间输出了以下的精品内容,期待您的关注。

相关文章
相关标签/搜索