Lucent's Blog

当时明月在 曾照彩云归

人生不相见,动如参与商。

6LCi5Y2O5qKFLOaIkeaDs+S9oOS6hg==


Stream的状态与并行操作

有状态与无状态

在编程中,经常会接触到“有状态”,“无状态”,绝大部分的人都比较蒙。而且在不同的场景下,“状态”这个词的含义似乎有所不同。

  • 状态通常代表公用数据,有状态就是有“公用数据”
  • 因为有公用的数据,状态通常需要额外的存储。
  • 状态通常被多人、多用户、多线程、多次操作,这就涉及到状态的管理及变更操作。

举个例子:

  • web开发session就是一种状态,访问者的多次请求关联同一个session,这个session需要存储到内存或者redis。多次请求使用同一个公用的session,这个session就是状态数据。
  • vue的vuex的store就是一种状态,首先它是多组件公用的,其次是不同的组件都可以修改它,最后它需要独立于组件单独存储。所以store就是一种状态。
  • 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元素去重

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

结果:

 ["Monkey", "Lion", "Giraffe", "Lemur"]

Sorted排序

默认的情况下,sorted是按照字母的自然顺序进行排序。

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

串行、并行与顺序

通常情况下,有状态和无状态操作不需要我们去关心。除非你使用了并行操作。

  • 串行的好处是可以保证顺序,但是通常情况下处理速度慢一些
  • 并行的好处是对于元素的处理速度快一些(通常情况下),但是顺序无法保证。这可能会导致进行一些有状态操作的时候,最后得到的不是你想要的结果。 例如:
Stream.of("Monkey", "Lion", "Giraffe", "Lemur", "Lion")
        .parallel()
        .forEach(System.out::println);

parallel()函数表示对管道中的元素进行并行处理,而不是串行处理。但是这样就有可能导致管道流中后面的元素先处理,前面的元素后处理,也就是元素的顺序无法保证。 第一次运行结果:

Giraffe
Lion
Lion
Monkey
Lemur

第二次运行结果:

Giraffe
Lion
Lemur
Lion
Monkey

通常情况下,parallel()能够很好的利用CPU的多核处理器,达到更好的执行效率和性能,建议使用。但是有些特殊的情况下,parallel并不适合。

  • 从处理性能的角度,parallel()更适合处理ArrayList,而不是LinkedList。因为ArrayList从数据结构上讲是基于数组的,可以根据索引很容易的拆分为多个。
  • 适用于无状态操作:每个元素的计算都不得依赖或影响任何其他元素的计算,的运算场景。
  • 从文本文件里面边读边处理的场景,不适合parallel()并行处理。parallel()一开始就容量固定的集合,这样能够平均的拆分、同步处理。

Stream管道流操作

78f74991175f6ddc5c27fff109f0fc66_942x578.png

上一篇

字符串List排序cities是一个字符串数组。注意london的首字母是小写的。List&lt;String&gt;cities=Arrays.asList(&quot;Milan&quot;,&quot;london&quot;,&quot;SanFrancisco&quot;,&quot;To…

阅读
下一篇

Stream管道流map的基础用法将集合中的每一个字符串,全部转换成大写:List&lt;String&gt;alpha=Arrays.asList(&quot;Monkey&quot;,&quot;Lion&quot;,&quot;Giraffe&quot;,&quot;Lemur&quot;);…

阅读