java理论基础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()一开始就容量固定的集合,这样能够平均的拆分、同步处理。

以上就是java理论基础Stream管道流状态与并行操作的详细内容,更多关于java Stream管道流状态与并行操作的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java8并行流中自定义线程池操作示例

    本文实例讲述了Java8并行流中自定义线程池操作.分享给大家供大家参考,具体如下: 1.概览 java8引入了流的概念,流是作为一种对数据执行大量操作的有效方式.并行流可以被包含于支持并发的环境中.这些流可以提高执行性能-以牺牲多线程的开销为代价 在这篇短文中,我们将看一下 Stream API的最大限制,同时看一下如何让并行流和线程池实例(ThreadPool instance)一起工作. 2.并行流Parallel Stream 我们先以一个简单的例子来开始-在任一个Collection类型

  • 用Java8 stream处理数据

    目录 1.stream处理数据介绍 2.Stream起步 3.Stream与Collection比较 1.stream处理数据介绍 如果没有集合Collection你如何处理数据?几乎所有的Java应用程序都要使用Collection处理数据.他们是十分重要的编程工作:例如,您可能想要创建银行交易的集合Collection,这个集合代表客户的状态.然后,你可能要处理整个集合来找出的顾客花了多少钱.尽管集合如此重要,但是在Java中处理集合的技术还远远不够完善. 首先,对集合的典型处理模式是类似S

  • Java 8 Stream流强大的原理

    目录 1.Stream的组成与特点 2.BaseStream接口 3.Stream接口 4.关闭流操作 5.并行流和串行流 6.ParallelStream背后的男人:ForkJoinPool 7.用ForkJoinPool的眼光来看ParallelStream 8.并行流的性能 9.NQ模型 10.遇到顺序 前言: Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象. Stream API可以极大提高Java程序员的生产力,让程

  • Java8的Stream()与ParallelStream()的区别说明

    Java8 Stream()与ParallelStream()区别 Stream 无状态:指元素的处理不受之前元素的影响: 有状态:指该操作只有拿到所有元素之后才能继续下去. 非短路操作:指必须处理所有元素才能得到最终结果: 短路操作:指遇到某些符合条件的元素就可以得到最终结果,如 A || B,只要A为true,则无需判断B的结果. ParallelStream 对于ParallelStream,需要知道的是里面的执行是异步的,并且使用的线程池是ForkJoinPool.common,可以通过

  • java理论基础Stream管道流状态与并行操作

    一.回顾Stream管道流操作 通过前面章节的学习,我们应该明白了Stream管道流的基本操作.我们来回顾一下: 源操作:可以将数组.集合类.行文本文件转换成管道流Stream进行数据处理 中间操作:对Stream流中的数据进行处理,比如:过滤.数据转换等等 终端操作:作用就是将Stream管道流转换为其他的数据类型.这部分我们还没有讲,我们后面章节再介绍. 看下面的脑图,可以有更清晰的理解: 二.中间操作:有状态与无状态 其实在程序员编程中,经常会接触到“有状态”,“无状态”,绝大部分的人都比

  • java基础理论Stream管道流Map操作示例

    目录 一.回顾Stream管道流map的基础用法 二.处理非字符串类型集合元素 三.再复杂一点:处理对象数据格式转换 四.flatMap 一.回顾Stream管道流map的基础用法 最简单的需求:将集合中的每一个字符串,全部转换成大写! List<String> alpha = Arrays.asList("Monkey", "Lion", "Giraffe", "Lemur"); //不使用Stream管道流 L

  • java理论基础Stream API终端操作示例解析

    目录 一.JavaStream管道数据处理操作 二.ForEach和ForEachOrdered 三.元素的收集collect 3.1.收集为Set 3.2.收集到List 3.3.通用的收集方式 3.4.收集到Array 3.5.收集到Map 3.6.分组收集groupingBy 四.其他常用方法 一.Java Stream管道数据处理操作 在本号之前写过的文章中,曾经给大家介绍过 Java Stream管道流是用于简化集合类元素处理的java API.在使用的过程中分为三个阶段.在开始本文之

  • java理论基础Stream reduce实现集合元素归约

    目录 Integer类型归约 String类型归约 复杂对象归约 Combiner合并器的使用 并行流数据归约(使用合并器) Stream API为我们提供了Stream.reduce用来实现集合元素的归约.reduce函数有三个参数: Identity标识:一个元素,它是归约操作的初始值,如果流为空,则为默认结果. Accumulator累加器:具有两个参数的函数:归约运算的部分结果和流的下一个元素. Combiner合并器(可选):当归约并行化时,或当累加器参数的类型与累加器实现的类型不匹配

  • java理论基础Stream元素的匹配与查找

    目录 一.对比一下有多简单 二.其他匹配规则函数介绍 三.元素查找与Optional 在我们对数组或者集合类进行操作的时候,经常会遇到这样的需求,比如: 是否包含某一个“匹配规则”的元素 是否所有的元素都符合某一个“匹配规则” 是否所有元素都不符合某一个“匹配规则” 查找第一个符合“匹配规则”的元素 查找任意一个符合“匹配规则”的元素 这些需求如果用for循环去写的话,还是比较麻烦的,需要使用到for循环和break!本节就介绍一个如何用Stream API来实现“查找与匹配”. 一.对比一下有

  • java理论基础Stream性能论证测试示例

    目录 一.粉丝的反馈 二.所有性能测试结论都是片面的 三.动手测试Stream的性能 3.1.环境 3.2.测试用例与测试结论 3.2.1.测试用例一 3.2.2测试用例二 3.2.3测试用例三 四.最终测试结论 五.测试代码 测试用例一: 测试用例二: 测试用例三: 一.粉丝的反馈 问:stream比for循环慢5倍,用这个是为了啥? 答:互联网是一个新闻泛滥的时代,三人成虎,以假乱真的事情时候发生.作为一个技术开发者,要自己去动手去做,不要人云亦云. 的确,这位粉丝说的这篇文章我也看过,我就

  • Java Stream函数式编程管道流结果处理

    目录 一.JavaStream管道数据处理操作 二.ForEach和ForEachOrdered 三.元素的收集collect 3.1.收集为Set 3.2.收集到List 一.Java Stream管道数据处理操作 在本号之前写过的文章中,曾经给大家介绍过 Java Stream管道流是用于简化集合类元素处理的java API.在使用的过程中分为三个阶段.在开始本文之前,我觉得仍然需要给一些新朋友介绍一下这三个阶段,如图: 第一阶段(图中蓝色):将集合.数组.或行文本文件转换为java Str

  • Java Stream函数式编程管道流结果处理

    目录 一.JavaStream管道数据处理操作 二.ForEach和ForEachOrdered 三.元素的收集collect 3.1.收集为Set 3.2.收集到List 3.3.通用的收集方式 3.4.收集到Array 3.5.收集到Map 3.6.分组收集groupingBy 四.其他常用方法 一.Java Stream管道数据处理操作 在本号之前写过的文章中,曾经给大家介绍过 Java Stream管道流是用于简化集合类元素处理的java API.在使用的过程中分为三个阶段.在开始本文之

  • Java 8 Stream操作类型及peek示例解析

    简介 java 8 stream作为流式操作有两种操作类型,中间操作和终止操作.这两种有什么区别呢? 我们看一个peek的例子: Stream<String> stream = Stream.of("one", "two", "three","four"); stream.peek(System.out::println); 上面的例子中,我们的本意是打印出Stream的值,但实际上没有任何输出. 为什么呢? 中间

随机推荐