【精通函数式编程】(四)流-Stream API原理解析

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 本文通过集合引出Stream流,主要讲解了流的基本概念、使用的原理,Stream流水线的运行原理

image.png

前言:

📫 作者简介:小明 java 问道之路,专注于研究计算机底层,就职于金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的设计和架构📫

🏆 Java 领域优质创作者、阿里云专家博主、华为云享专家🏆

🔥 如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主哦

本文导读

集合是java中使用最多的数据结构,我们如何处理大量元素就是个问题,多线程(线程池)+迭代器性能是还可以,但是太麻烦,也不利于开发和管理,并发的问题还要考虑,这个时候为了保证java的流行性,或者说为了不让java淘汰,在高版本搞出来 流(Stream)。

一、集合与流

集合是java中使用最多的数据结构,包括List、Map,面向对象编程更像是面向集合面向数据结构编程,当我们要处理大量元素的时候,往往会使用多线程,多线程还不能直接创建,要使用线程池创建,麻烦的一批(Java开发规范);

我们如何处理大量元素就是个问题,多线程(线程池)+迭代器性能是还可以,但是太麻烦,也不利于开发和管理,并发的问题还要考虑,这个时候为了保证java的流行性,或者说为了不让java淘汰,在高版本搞出来 流(Stream)。

流(Stream)是声明式处理集合的,我们可以把他当做一个高级的 迭代器+多线程容器,他不能简单理解为一个 流 数据结构,集合(List、Map)可以增删改查,虽然流可以实现诸如过滤、合并,分组等等操作,但是其元素是 按需计算,这其实是一种生产者-消费者模式,流就像一个 正在创建的集合,他会按要求变化后计算值。

下面三段代码,for循环遍历list + if、list转迭代器 + if、等同逻辑

// for + if
        List<BigDecimal> orderAmt = new ArrayList<>();
        for (OrderInfo orderInfo : orderInfos) {
            if (orderInfo.getOrderAmt().compareTo(BigDecimal.ZERO) > 0) {
                orderAmt.add(orderInfo.getOrderAmt());
            }
        }
        // 迭代器 + if
        Iterator<OrderInfo> it = orderInfos.iterator();
        while (it.hasNext()) {
            OrderInfo orderInfo = it.next();
            if (orderInfo.getOrderAmt().compareTo(BigDecimal.ZERO) > 0) {
                orderAmt.add(orderInfo.getOrderAmt());
            }
        }
        // Stream流 + Lambda表达式
        List<BigDecimal> collect = orderInfos.stream()
                .filter(orderInfo -> orderInfo.getOrderAmt().compareTo(BigDecimal.ZERO) > 0)
                .map(orderInfo -> orderInfo.getOrderAmt()).collect(Collectors.toList());

二、什么是流

流是Java 高版本的API,是声明式处理集合的,声明式(简洁)就是说我想要做什么而不是如何实现,把他当做一个高级的 迭代器(可复合-灵活)+多线程容器(可并行-性能好)

要了解流是什么,还要了解他的定义、类路径、如何使用,以及一些使用规范

流在 java.util.stream.Stream 接口中定义,我们可以看到接口注释中有大量讲解,我们就根据这些注释学习流

我们看源码,该类里面有大量方法接口(就和集合一样),可以访问元素,但是集合是数据结构,所以他主要目的是使用特定算法和数据结构存储/访问元素;但流的目的是计算。Stream<T> 流的接收元素是泛型,流会使用一个数据源(这个数据源流不会改变顺序)

image.png

注释中说了,1、流是懒加载原则;仅当 端操作启动时才对源数据执行计算,并且仅在需要时消耗源元素;2、流不会改变原有的数据源;3、流只操作一次;4、可能会抛出 IllegalStateException;5、流不需要被关闭;6、流是内部迭代。详细论证我们放到下面

三、流的使用原则

流使用包括3件事,要有数据源来执行操作,要有一个链这个链试试中间操作的步骤,一个终端操作生成结果。下面代码会论证 这些原则以及上述原理

流只能遍历一次,且是按顺序遍历(流是按顺序遍历的,不会一个List都过滤完,才map,而是每个元素都是流水线执行的)

// 流是按顺序遍历的,不会一个List都过滤完,才map,而是每个元素都是流水线执行的
List<BigDecimal> collect = orderInfos.stream().filter(orderInfo -> {
    System.out.println("===filter" + orderInfo.getOrderAmt());
    return orderInfo.getOrderAmt().compareTo(BigDecimal.ZERO) > 0;
}).map(orderInfo -> {
    System.out.println("===map" + orderInfo.getOrderAmt());
    return orderInfo.getOrderAmt();
}).collect(Collectors.toList());
System.out.println(collect);
// 流只能操作一次,当再次使用的时候会报错IllegalStateException:operated upon or closed
Stream<BigDecimal> stream = collect.stream();
stream.forEach(System.out::print);
System.out.println("===========");
stream.forEach(System.out::print);

image.png

流,java.util.stream.Stream 接口中定义 很多方法,这些方法分为 两大类。filter、map、limit、forEach、peek 等,可以连成流水线;collect 触发流水线执行并关闭(终端操作)。我们把连接起来称为中间操作,关闭流的称为终端操作。一个流的使用原则就是要有数据源、中间操作、终端从操作

四、流的运行原理

为什么Stram流、Lamda表达式式写法又叫作函数式编程?一是调用手法像是函数一般,只须传入参数即可调用;二是Lamda实现方式为生出静态函数调用而成

下图执行步骤标号 1 2 3 4,那流是如何 解决 Stream流水线的?

image.png

Stream中用某种实例化后的PipelineHelper来代表Stage,将具有先后顺序的各个Stage连到一起,就构成了整个流水线。跟Stream相关类和接口的继承关系图示。

image.png

上图中Head用于表示第一个Stage,即调用调用诸如Collection.stream()方法产生的Stage,很显然这个Stage里不包含任何操作;StatelessOp和StatefulOp分别表示无状态和有状态的Stage,对应于无状态和有状态的中间操作。

下图中通过Collection.stream()方法得到Head也就是stg0,紧接着调用一系列的中间操作,不断产生新的Stream。这些Stream对象以双向链表的形式组织在一起,构成整个流水线,由于每个Stage都记录了前一个Stage和本次的操作以及回调函数,依靠这种结构就能建立起对数据源的所有操作。这就是Stream记录操作的方式。

image.png

小结

本文通过集合引出Stream流,主要讲解了流的基本概念、使用的原理,Stream流水线的运行原理。

相关文章
|
8天前
|
存储 缓存 监控
如何高效爬取天猫商品数据?官方API与非官方接口全解析
本文介绍两种天猫商品数据爬取方案:官方API和非官方接口。官方API合法合规,适合企业长期使用,需申请企业资质;非官方接口适合快速验证需求,但需应对反爬机制。详细内容涵盖开发步骤、Python实现示例、反爬策略、数据解析与存储、注意事项及扩展应用场景。推荐工具链包括Playwright、aiohttp、lxml等。如需进一步帮助,请联系作者。
|
9天前
|
机器学习/深度学习 JSON 算法
淘宝拍立淘按图搜索API接口系列的应用与数据解析
淘宝拍立淘按图搜索API接口是阿里巴巴旗下淘宝平台提供的一项基于图像识别技术的创新服务。以下是对该接口系列的应用与数据解析的详细分析
|
9天前
|
数据可视化 测试技术 API
前后端分离开发:如何高效调试API?有工具 vs 无工具全解析
在前后端分离的开发模式中,API 调试的效率直接影响项目的质量和交付速度。通过本文的对比分析,我们可以看到无工具调试模式虽具备灵活性和代码复用能力,但在操作便利性和团队协作上稍显不足。而传统的外部调试工具带来了可视化、高效协作与扩展性,却可能存在工具切换带来的开发链路断层问题。Apipost-Hepler 融合了两者的优势,让开发者无需离开熟悉的 IDEA 环境,就能享受可视化调试工具的强大功能。
40 5
|
9天前
|
JSON API 数据格式
淘宝商品评论API接口系列的应用与数据解析
在电商平台中,用户评论是了解商品质量、服务水平和用户满意度的重要数据来源。淘宝作为中国最大的电商平台,提供了商品评论API接口,帮助开发者获取和分析用户评价数据。本文将介绍淘宝商品评论API接口系列的作用、使用方法,并通过示例展示如何调用API并解析返回的JSON数据。
|
9天前
|
机器学习/深度学习 数据可视化 PyTorch
深入解析图神经网络注意力机制:数学原理与可视化实现
本文深入解析了图神经网络(GNNs)中自注意力机制的内部运作原理,通过可视化和数学推导揭示其工作机制。文章采用“位置-转移图”概念框架,并使用NumPy实现代码示例,逐步拆解自注意力层的计算过程。文中详细展示了从节点特征矩阵、邻接矩阵到生成注意力权重的具体步骤,并通过四个类(GAL1至GAL4)模拟了整个计算流程。最终,结合实际PyTorch Geometric库中的代码,对比分析了核心逻辑,为理解GNN自注意力机制提供了清晰的学习路径。
158 7
深入解析图神经网络注意力机制:数学原理与可视化实现
|
10天前
|
存储 自然语言处理 监控
深度解析淘宝商品评论API接口:技术实现与应用实践
淘宝商品评论API接口是电商数据驱动的核心工具,帮助开发者高效获取用户评价、画像及市场趋势。其核心功能包括多维度信息采集、筛选排序、动态更新、OAuth 2.0认证和兼容多种请求方式。通过该接口,开发者可进行商品优化、竞品分析、舆情监控等。本文详细解析其技术原理、实战应用及挑战应对策略,助力开启数据驱动的电商运营新篇章。
|
10天前
|
机器学习/深度学习 缓存 自然语言处理
深入解析Tiktokenizer:大语言模型中核心分词技术的原理与架构
Tiktokenizer 是一款现代分词工具,旨在高效、智能地将文本转换为机器可处理的离散单元(token)。它不仅超越了传统的空格分割和正则表达式匹配方法,还结合了上下文感知能力,适应复杂语言结构。Tiktokenizer 的核心特性包括自适应 token 分割、高效编码能力和出色的可扩展性,使其适用于从聊天机器人到大规模文本分析等多种应用场景。通过模块化设计,Tiktokenizer 确保了代码的可重用性和维护性,并在分词精度、处理效率和灵活性方面表现出色。此外,它支持多语言处理、表情符号识别和领域特定文本处理,能够应对各种复杂的文本输入需求。
50 6
深入解析Tiktokenizer:大语言模型中核心分词技术的原理与架构
|
1天前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
41 29
|
8天前
|
存储 前端开发 JavaScript
在线教育网课系统源码开发指南:功能设计与技术实现深度解析
在线教育网课系统是近年来发展迅猛的教育形式的核心载体,具备用户管理、课程管理、教学互动、学习评估等功能。本文从功能和技术两方面解析其源码开发,涵盖前端(HTML5、CSS3、JavaScript等)、后端(Java、Python等)、流媒体及云计算技术,并强调安全性、稳定性和用户体验的重要性。
|
10天前
|
移动开发 前端开发 JavaScript
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。

热门文章

最新文章

推荐镜像

更多