广告
返回顶部
首页 > 资讯 > 后端开发 > Python >解析Java8 Stream原理
  • 767
分享到

解析Java8 Stream原理

2024-04-02 19:04:59 767人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录一、前言二、Stream流水线解决方案2.1、操作如何记录2.2、操作如何叠加2.3、叠加之后的操作如何执行一、前言 首先我们先看一个使用Stream api的示例,具体代码如下

一、前言

首先我们先看一个使用Stream api的示例,具体代码如下:

这是个很简单的一个Stream使用例子,我们过滤掉空字符串后,转成int类型并计算出最大值,这其中包括了三个操作:filter、mapToInt、sum。相信大多数人再刚使用Stream API的时候都会有个疑问,Stream是指怎么实现的,是每一次函数调用就执行一次迭代吗?答案肯定是否,因为如果真的是每一次函数调用就执行一次迭代,这个效率是很难接受的,Stream也不会那么受欢迎。

其实Stream内部是通过流水线(Pipeline)的方式来实现的,基本思想是在迭代的时候顺着流水线尽可能的执行更多的操作,从而避免多次迭代。为了对Stream的操作有更清晰的认识,我们汇总了Stream的所有操作。

从上表可以看出Stream将所有操作分为两类:中间操作和终止操作。其中中间操作分为无状态和有状态,终止操作分为非短路操作和短路操作,下面是针对这几个操作的含义说明:

1、中间操作:中间操作只是一种标记,只有结束操作才会触发实际计算

  • 无状态:指元素的处理不受前面元素的影响;
  • 有状态:有状态的中间操作必须等到所有元素处理之后才知道最终结果,比如排序是有状态操作,在读取所有元素之前并不能确定排序结果。

2、终止操作:顾名思义,就是得出最后计算结果的操作

  • 短路操作:指不用处理全部元素就可以返回结果;
  • 非短路操作:指必须处理所有元素才能得到最终结果。

二、Stream流水线解决方案

通过上面的介绍,我们了解到Stream在执行中间操作时仅仅是记录,当用户调用终止操作时,会在一个迭代里将已经记录的操作顺着流水线全部执行掉。沿着这个思路,有几个问题需要解决:

  • 用户的操作如何记录?
  • 操作如何叠加?
  • 叠加之后的操作如何执行?

2.1、操作如何记录

图1-1

关于操作如何记录,在jdk源码注释中多次用(操作)stage来标识用户的每一次操作,而通常情况下Stream的操作又需要一个回调函数,所以一个完整的操作是由数据来源、操作、回调函数组成的三元组来表示。而在具体实现中,使用实例化的ReferencePipeline来表示,即图1-1中的Head、StatelessOp、StatefulOp的实例。接下来我们来看下Stream几个常用方法的源码。

code2 Collection.Stream()

code3StreamSupport.stream()

code4 ReferencePipeline.map()

从上面源码中可以看出来,我们调用stream()方法时最终会创建一个Head实例来表示流操作的头,当调用map()方法时则会创建无状态的中间操作实例StatelessOp,同样调用其他操作对应的方法也会生成一个ReferencePipeline实例,在这里就不一一列举。在用户调用一系列操作后,最终会形成一个双向链表,如下图所示:

图1-2

2.2、操作如何叠加

上面我们说明了Stream是通过stage记录操作,但stage只保存当前操作,它并不知道下个stage如何操作,需要什么操作。所以要执行的话还需要某种协议将各个stage关联起来。jdk中就是使用Slink接口来实现的,Slink接口定义begin()、end()、cancellationRequested()、accept()四个方法,如下表所示。

往回看code3 ReferencePipeline.map()的方法,我们会发现我们在创建一个ReferencePipeline实例的时候,需要重写opWrapSink方法来生成对应Sink实例。而且通过阅读源码会发现常用的操作都会创建一个ChainedReference实例。我们可以看下code5 ChainedReference抽象类的源码实现,因为ChainedReference只是个抽象实现,不携带具体操作的特性,所以是更能体现作者的设计理念。

通过查看源码可以发现ChainedReference会持有下一个操作的Slink,并在调用begin、end、cancellationRequested方法会调用下一个操作的Slink的相应方法,以此来达到叠加的效果。

code5ChainedReference

2.3、叠加之后的操作如何执行

Sink完美封装了Stream每一步操作,并给出了[处理->转发]的模式来叠加操作。这一连串的齿轮已经咬合,就差最后一步拨动齿轮启动执行。是什么启动这一连串的操作呢?也许你已经想到了启动的原始动力就是结束操作(Terminal Operation),一旦调用某个结束操作,就会触发整个流水线的执行。

结束操作之后不能再有别的操作,所以结束操作不会创建新的流水线阶段(Stage),直观的说就是流水线的链表不会在往后延伸了。结束操作会创建一个包装了自己操作的Sink,这也是流水线中最后一个Sink,这个Sink只需要处理数据而不需要将结果传递给下游的Sink(因为没有下游)。对于Sink的[处理->转发]模型,结束操作的Sink就是调用链的出口。

我们再来考察一下上游的Sink是如何找到下游Sink的。一种可选的方案是在PipelineHelper中设置一个Sink字段,在流水线中找到下游Stage并访问Sink字段即可。但Stream类库的设计者没有这么做,而是设置了一个Sink AbstractPipeline.opWrapSink(int flags, Sink downstream)方法来得到Sink,该方法的作用是返回一个新的包含了当前Stage代表的操作以及能够将结果传递给downstream的Sink对象。为什么要产生一个新对象而不是返回一个Sink字段?这是因为使用opWrapSink()可以将当前操作与下游Sink(上文中的downstream参数)结合成新Sink。试想只要从流水线的最后一个Stage开始,不断调用上一个Stage的opWrapSink()方法直到最开始(不包括stage0,因为stage0代表数据源,不包含操作),就可以得到一个代表了流水线上所有操作的Sink,用代码表示就是这样:

code6AbstractPipeline.wrapSink

现在流水线上从开始到结束的所有的操作都被包装到了一个Sink里,执行这个Sink就相当于执行整个流水线,执行Sink的代码如下:

code7AbstractPipeline.copyInto

上述代码首先调用wrappedSink.begin()方法告诉Sink数据即将到来,然后调用spliterator.forEachRemaining()方法对数据进行迭代,最后调用wrappedSink.end()方法通知Sink数据处理结束。逻辑如此清晰。

以上就是解析Java8 Stream原理的详细内容,更多关于Java8 Stream原理的资料请关注编程网其它相关文章!

--结束END--

本文标题: 解析Java8 Stream原理

本文链接: https://www.lsjlt.com/news/128399.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 解析Java8 Stream原理
    目录一、前言二、Stream流水线解决方案2.1、操作如何记录2.2、操作如何叠加2.3、叠加之后的操作如何执行一、前言 首先我们先看一个使用Stream API的示例,具体代码如下...
    99+
    2022-11-12
  • Java8中的Stream的原理是什么
    本篇内容主要讲解“Java8中的Stream的原理是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java8中的Stream的原理是什么”吧!Stream的组成与特点Stream(流)是一个...
    99+
    2023-06-15
  • Java8 自定义CompletableFuture的原理解析
    目录Java8 自定义CompletableFuture原理CompleteFuture简单使用下面简单介绍用法Java8 自定义CompletableFuture原理 Future...
    99+
    2022-11-12
  • Java7和Java8中的ConcurrentHashMap原理解析
    目录Java7 中 ConcurrentHashMap初始化put 过程分析初始化槽: ensureSegment获取写入锁: scanAndLockForPut扩容: rehash...
    99+
    2022-11-12
  • 用Java8 stream处理数据
    目录1、stream处理数据介绍2、Stream起步3、Stream与Collection比较1、stream处理数据介绍   如果没有集合Collection你如何处理数据?几乎所...
    99+
    2022-11-12
  • Java8新特性Stream流详解
    陈老老老板 说明:新的专栏,本专栏专门讲Java8新特性,把平时遇到的问题与Java8的写法进行总结,需要注意的地方都标红了,一起加油。 本文是介绍Java8新特性Stream流常用方法超详细教学 ...
    99+
    2023-08-17
    java 算法 数据结构
  • Java8新特性Stream流的示例分析
    这篇文章主要介绍Java8新特性Stream流的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!什么是Stream流?Stream流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。Stream的优点...
    99+
    2023-05-30
    java8 stream流
  • Java8中Stream API操作的示例分析
    这篇文章主要介绍了Java8中Stream API操作的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1.什么是StreamAPI?Java8中有两大最为重要的改变。...
    99+
    2023-06-25
  • 详解java8中的Stream数据流
    Stream是java8引入的一个重度使用lambda表达式的API。Stream使用一种类似用SQL语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象。直观意味着开发者在写代码时只需关注他们想要的结果是什么而无需关...
    99+
    2023-05-31
    java8 stream 数据流
  • Java8新特性之Stream API详解
    目录一、前言二、使用流程三、案例演示一、前言 StreamAPI在Java8版本中使用,关注的是对数据的筛选、查找、存储等 它可以做的事情有:过滤、排序、映射、归约 二、使用流程 S...
    99+
    2022-11-12
  • JAVA8 Stream流中的reduce()方法详解
    目录reduce()简介reduce三个override的方法公共集合reduce()简介 Reduce 原意:减少,缩小根据指定的计算模型将Stream中的值计算得到一个...
    99+
    2023-02-28
    JAVA8 Stream reduce()方法 JAVA8 Stream reduce
  • Java8 Stream之groupingBy分组使用解读
    目录Java8 Stream之groupingBy分组Collectors.groupingBy()分组之常见用法Collectors.groupingBy() 分组之统计每个分组的...
    99+
    2023-05-17
    Java8 Stream groupingBy分组 Java8 groupingBy分组
  • 详解Java8 Stream Api中map和flatMap操作
    1.前言Java 8 提供了非常好用的 Stream API ,可以很方便的操作集合。今天我们来探讨两个 Stream 中间操作 map(Function...
    99+
    2017-11-17
    java入门 java map flatMap
  • 深入理解Java8新特性之Stream API的终止操作步骤
    目录1.写在前面2.终止操作2.1 终止操作之查找与匹配2.2 终止操作之归约与收集1.写在前面 承接了上一篇文章(说完了Stream API的创建方式及中间操作):深入理解Java...
    99+
    2022-11-12
  • SpringCloud Stream使用解析
    目录SpringCloudStream下面用RabbitMQ来说明使用!案例之消息驱动之生产者案例之消息驱动消费者测试补充说明SpringCloudStream 官方定义Sprin...
    99+
    2022-11-12
  • Java8利用Stream实现列表去重的方法详解
    目录一. Stream 的distinct()方法1.1 对于 String 列表的去重1.2 对于实体类列表的去重二. 根据 List<Object> 中 Object...
    99+
    2022-11-13
  • java8 Stream大数据量List分批处理切割方式
    目录java8 Stream大数据量List分批处理java8部分特性及list的常见操作Lambda表达式常见的list操作总结java8 Stream大数据量List分批处理 /...
    99+
    2023-02-15
    java8 Stream 大数据量List处理 大数据分批处理切割
  • Java8中ConcurrentHashMap的原理是什么
    这期内容当中小编将会给大家带来有关Java8中ConcurrentHashMap的原理是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序...
    99+
    2023-06-14
  • myloader原理解析
    ...
    99+
    2022-10-18
  • 解析HOT原理
    2020-06-09 19:31:01 一、疑问   前段时间;QQ群里有人对“这个表(0,4)这行数据我做了update操作,查看索引的page数据,看到索引一直指向(0,4),用ctid="(0,4)"查询业务表是查...
    99+
    2017-07-31
    解析HOT原理
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作