当前位置: 首页 > news >正文

【学习笔记】Java函数式编程03 Stream流-终结操作

书接上回

3.3.3 终结操作

3.3.3.1 forEach

对集合的每一个元素进行处理

接触很多了不赘述

3.3.3.2 count

用来获取当前流中的元素的个数

比如,打印出所有作家的作品的总数

System.out.println(authors.stream().flatMap(author -> author.getBooks().stream()).count());
3.3.3.3 max和min

可以用来流中的最值。

查看源码可以发现这个方法是需要传入参数的

Optional<T> max(Comparator<? super T> comparator);
Optional<T> min(Comparator<? super T> comparator);

Comparator是一个比较器,但是这里的比较器是什么作用呢?其实stream流的球最值和前面的sorted的实现逻辑类似,都是要求先比较排序后再求最值

另外,这个方法的返回值是Optional类型,这个类型后续会再细讲。

所以max和min不用死记,学会sorted就可以满足需要了

3.3.3.4 ⭐️collect

将流当中的元素转换为一个集合(List/Set/Map)。

阅读源码可以发现collect的两个参数都非常复杂,在实际使用中会使用工具类的方法来快速实现

image-20231212172433634

小练习快速上手

1、获取一个所有作者名字的集合List

authors.stream().map(Author::getName).collect(Collectors.toList())

2、获取一个所有书名的集合SET

authors.stream().flatMap(author -> author.getBooks().stream()).map(Book::getName).collect(Collectors.toSet());

顺带一提,由于set的去重作用,所有其实前面提到的“去重“的需求,也可以尝试用collect来实现

3、获取一个map集合,Key为作者名,Value为作品集List

沿用前面的思路,利用Collectors.toMap方法实现,但是转map是需要指定key和v的,研究toMap方法就可以发现:这里确实要求传入两个Function函数式接口,如下

image-20231221102613795

尝试先写一个匿名内部类的原生写法,然后进行简化:

// 获取一个map集合,Key为作者名,Value为作品集List
List<Author> authors = Author.getAuthor(5);
Map<String, List<Book>> map = authors.stream().collect(Collectors.toMap(new Function<Author, String>() {@Overridepublic String apply(Author author) {return author.getName();}}, new Function<Author, List<Book>>() {@Overridepublic List<Book> apply(Author author) {return author.getBooks();}}));System.out.println(map);// 第一次简化
authors.stream().collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));// IDEA提供的进一步简化
authors.stream().collect(Collectors.toMap(Author::getName, Author::getBooks));

不难发现,toMap方法就是分别指定key和value就可以实现转map的要求了

4、获取一个map集合,Key为作者名,Value为作者

注意:需求不同,这次是将val作为作者本身的对象,这个其实也是比较常见的需求

Map<String, List<Author>> collect = author.stream().collect(Collectors.groupingBy(new Function<Author, String>() {@Overridepublic String apply(Author author) {return author.getName();}}));// 简化后
author.stream().collect(Collectors.groupingBy(Author::getName));

介绍完简单的终结操作后,接下来还有一些比较复杂的操作。比如需求场景

  • 判断是否有25岁以上的作家?
  • 判断是不是所有作家都刚满18岁?

3.3.4 终结操作之查找与匹配

3.3.4.1 anyMatch

任一元素符合条件,则返回true

3.3.4.2 allMatch

所有符合条件,则返回true

3.3.4.3 nonMatch

所有的元素都不符合条件

(这个不需要硬记,和allMatch互为补集)


3.3.4.4 findAny

image-20231221112305126

这个操作用于获取流中的任意一个元素,注意,这个操作无法保证获取的是第一个元素

3.3.4.5 findFirst

这个操作用于获取流中的第一个元素。

  • 这个终结操作一般需要结合limitsorted使用

补充说明

这两个方法返回的对象是JDK8新增的Optional对象,用于避免空指针等异常的,后续会详细介绍。

  • 要获取里面的对象使用get()方法即可。
  • ifPresent()方法可以在对象存在时,执行方法内的函数

3.3.5 ⭐️终结操作之归并操作-reduce

reduce单词字面意思有减少的意思,可以引申为缩小、裁剪的意思

image-20231226144739020

3.3.5.1 reduce概念

对流中的数据,按照指定的计算方式,计算出一个结果。(缩紧操作)

reduce的作用,将stream中的元素“组合”起来,最终传出组合的结果,起到一个紧缩、简化的作用。

两种实现方式

  • 传入一个初始值,按照给定的计算方式以此与流中的每个元素进行“计算”,每次计算得到的结果都可以和后面的元素再进行计算,并最终给出结果。
  • 没有初始值,而是将第一个元素给定为初始值,然后以此和流内的其他元素进行“计算”并给出结果。

两种方式对应reduce的两种重写方式

  • T reduce(T identity, BinaryOperator<T> accumulator);
  • Optional<T> reduce(BinaryOperator<T> accumulator);
3.3.5.2 reduce有初始值的重写

T reduce(T identity, BinaryOperator<T> accumulator);

查看源码注释可以发现,双参数的实现逻辑如下:

T result = identity;  
for (T element : this stream)      result = accumulator.apply(result, element)  return result;

做两个求最值的快速练习——求出所有作家的最大年纪

List<Author> authors = Author.getAuthor();
// 先打印出每个作家的年纪
authors.stream().map(Author::getAge).sorted().forEach(System.out::println);
System.out.println("-----------------");
// 求最大值 匿名内部类写法
Integer max = authors.stream().map(Author::getAge).reduce(Integer.MIN_VALUE, new BinaryOperator<Integer>() {@Overridepublic Integer apply(Integer element, Integer next) {return element < next ? next : element;}});
System.out.println(max);
// 求最大值 lambda简化
Integer max1 = authors.stream().map(Author::getAge).reduce(Integer.MIN_VALUE, (element, next) -> element < next ? next : element);
System.out.println(max1);

顺带一提前面学到的max()和min()底层就是使用reduce实现的

3.3.5.3 reduce无初始值的调用

Optional<T> reduce(BinaryOperator<T> accumulator);

实现低层逻辑是这样的:

boolean foundAny = false;  
T result = null;  
for (T element : this stream) {      if (!foundAny) {          foundAny = true;         result = element;      }     else          result = accumulator.apply(result, element);  
}  
return foundAny ? Optional.of(result) : Optional.empty();

逻辑就是:

  • 第一个元素给定为初始值,然后以此和流内的其他元素进行“计算”并给出结果。
  • 由于如果流为空返回的对象可能为空,所有这里使用了Optional进行包装

做个练习,一样是求最大年纪

// 匿名内部类原生写法
Optional<Integer> optional = authors.stream().map(Author::getAge).reduce(new BinaryOperator<Integer>() {@Overridepublic Integer apply(Integer element, Integer next) {return element < next ? next : element;}});
//  lambda简化
Optional<Integer> optional1 = authors.stream().map(Author::getAge).reduce((element, next) -> element < next ? next : element);
optional.ifPresent(System.out::println);
optional1.ifPresent(System.out::println);

3.4 Stream流的注意事项

  • 惰性求值
  • 一次性流
  • 不会影响原数据

3.4.1 惰性求值

没有任何终结操作,前面的中间操作都不会得到执行和保留。

  • 实际开发过程中,由于没有终结操作的stream写法并不会编译报错
  • 所以在写代码的时候一定要养成添加终结操作的习惯)

3.4.2 流是一次性的

在进行终结操作后,流会失效(报废。

举个例子:

在这里插入图片描述

  • 在实际开发过程中,使用stream流应该在调用stream()方法后就使用链式编程直到终结操作
  • 如果需要再次操作,就重新调用并生成新的流即可

3.4.3 不会影响原数据

特指是正常操作,而且这也是选择stream流所期望的。

举个例子,在map操作中将年龄+10,其实集合中元素的年龄是不会变化的。

image-20231226161532252

  • 在实际开发中,如果是需要对集合的元素进行操作时,则不建议使用stream流
  • 使用了stream流也应该尽量避免对集合中的元素进行操作(增删改)

相关文章:

【学习笔记】Java函数式编程03 Stream流-终结操作

书接上回 3.3.3 终结操作 3.3.3.1 forEach 对集合的每一个元素进行处理 接触很多了不赘述 3.3.3.2 count 用来获取当前流中的元素的个数 比如&#xff0c;打印出所有作家的作品的总数 System.out.println(authors.stream().flatMap(author -> author.getBooks().stre…...

2024 Android保活总结

本文介绍的方案都是无需用户主动开启权限的。如果需要用户主动开启权限或者加白名单之类的话保活的意义就不大了&#xff0c;毕竟用户不大可能主动原因让app一直在后台运行 常规的方案 OnePixelActivity 1&#xff0c;监听SCREEN_OFF启动一个像素的Activity&#xff0c;灭屏…...

迅为RK3568开发板Ubuntu上使用串口调试

我们也可以在虚拟机的 Ubuntu 上使用调试串口。首先要参考 11 手册安装好 Ubuntu20.04。在 Ubuntu上可以安装多种串口工具&#xff0c;比如 minicom&#xff0c;picocom&#xff0c;kermit。本章节我们来介绍 minicom 的安装和使用。 输入以下命令安装 minicomapt-get install…...

【http】HTTP/1.0、HTTP/1.1和HTTP/2.0

✨ 专栏介绍 在当今互联网时代&#xff0c;计算机网络已经成为了人们生活和工作中不可或缺的一部分。而要实现计算机之间的通信和数据传输&#xff0c;就需要依靠各种网络协议来进行规范和约束。无论是浏览网页、发送电子邮件还是进行在线交流&#xff0c;都离不开各种各样的网…...

automkcert使用教程

我们在开发的时候往往需要https开启一些浏览器功能,比如摄像头、wss等&#xff0c;自己的云服务器申请证书一个是麻烦&#xff0c;一个是价格贵&#xff0c;这种情况下可以用自签名证书。但自签名证书下有不通用的特点&#xff0c;其他机器无法快速信任自己的网站&#xff0c;因…...

tekton 发布 kubernetes 应用

tekton 发布 kubernetes 应用 基于Kubernetes 服务部署 Tekton Pipeline 实例&#xff0c;部署完成后使用tekton来完成源码拉取、应用打包、镜像推送和应用部署。 本文实现一个 golang-helloworld 项目 CI/CD 的完整流程&#xff0c;具体包括以下步骤&#xff1a; 从 gitee…...

unity脚本API中OnCollisionEnter()、OnTriggerEnter()二者的区别

Unity中的OnCollisionEnter和OnTriggerEnter两个函数在日常的开发中很常见但也容易混淆&#xff0c;下面说一说两者的区别。 碰撞器&#xff08;Collider&#xff09;与触发器&#xff08;Trigger&#xff09;的概念 碰撞器&#xff08;Collider&#xff09;和触发器&#xff…...

2023年12月【考试战报】|ORACLE OCP 19C考试通过

2023年10月【考试战报】|ORACLE OCP 19C考试通过-CSDN博客文章浏览阅读122次。自OCP认证进入中国以来&#xff0c;越来越被大多数DBA所认可&#xff0c;也越来越被企业所重视&#xff0c;90%以上DBA深造&#xff0c;都会选择OCP认证。随着OCP认证在全国范围内的普及&#xff0c…...

鸿蒙操作系统:从手机到物联网,打造全场景智能体验

随着科技的不断发展&#xff0c;人们对于操作系统的需求也在不断升级。鸿蒙操作系统&#xff0c;作为华为推出的新一代智能终端操作系统&#xff0c;凭借其强大的分布式能力、流畅的用户体验以及丰富的应用生态&#xff0c;正逐渐成为人们关注的焦点。 一、鸿蒙操作系统概述 …...

[Ray Tracing: The Next Week] 笔记

前言 本篇博客参照自《Ray Tracing: The Next Week》教程&#xff0c;地址为&#xff1a;https://raytracing.github.io/books/RayTracingTheNextWeek.html 该教程在ray tracing in one weekend的基础上&#xff0c;增加了运动模糊、BVH树、Texture映射、柏林噪声、光照、体积…...

企业级实战项目:基于 pycaret 自动化预测公司是否破产

本文系数据挖掘实战系列文章&#xff0c;我跟大家分享一个数据挖掘实战&#xff0c;与以往的数据实战不同的是&#xff0c;用自动机器学习方法完成模型构建与调优部分工作&#xff0c;深入理解由此带来的便利与效果。 1. Introduction 本文是一篇数据挖掘实战案例&#xff0c;…...

dl转置卷积

转置卷积 转置卷积&#xff0c;顾名思义&#xff0c;通过名字我们应该就能看出来&#xff0c;其作用和卷积相反&#xff0c;它可以使得图像的像素增多 上图的意思是&#xff0c;输入是22的图像&#xff0c;卷积核为22的矩阵&#xff0c;然后变换成3*3的矩阵 代码如下 import…...

详解结构体(包含结构体内存对齐,柔性数组,位段)【尊嘟很详细】

​ 结构体 结构体是一些值的集合&#xff0c;这些值称为成员变量&#xff0c;结构的成员可以是标量、数组、指针,甚至是其他结构体。 成员名可以与程序中其它变量同名&#xff0c;互不干扰。 结构体的定义 &#xff08;struct结构名{}&#xff09; struct books {int a;c…...

我的NPI项目之Android系统升级 - 同平台多产品的OTA

因为公司业务中涉及的面比较广泛&#xff0c;虽然都是提供移动终端PDA&#xff0c;但是使用的场景很多时候是不同的。例如&#xff0c;有提供给大型物流仓储的设备&#xff0c;对这样的设备必需具备扫码功能&#xff0c;键盘&#xff08;戴手套操作&#xff09;&#xff0c;耐用…...

pnpm包管理器

官网 优点 快速 pnpm 比 npm 快了近 2 倍高效 node_modules 中的所有文件均克隆或硬链接自单一存储位置支持单体仓库 pnpm 内置了对单个源码仓库中包含多个软件包的支持权限严格 pnpm 创建的 node_modules 默认并非扁平结构&#xff0c;因此代码无法对任意软件包进行访问 安…...

flutter websocket发送ping包?

背景 服务端要求flutter客户端隔一段时间发送ping包&#xff0c;以此来建立心跳管理长连接。 代码 import package:web_socket_channel/io.dart; IOWebSocketChannel _channel IOWebSocketChannel.connect(Uri.parse(SocketService.url),pingInterval: const Duration(seco…...

基于采样的自动驾驶规划算法 - PRM,RRT,RRT*,CL-RRT

本文将讲解PRM&#xff0c;RRT&#xff0c;RRT*自动驾驶规划算法原理&#xff0c;不正之处望读者指正 0 前言 机器人运动规划的基本任务&#xff1a;从开始位置到目标位置的运动 &#xff08;1&#xff09;如何躲避构型空间出现的障碍物 &#xff08;2&#xff09;如何满足机器…...

CGAL的D维范围树和线段树

范围树和线段树是两种数据结构&#xff0c;用于高效地处理和查询数据。 范围树&#xff08;Range Tree&#xff09;是一种二叉树&#xff0c;它通过递归地将每个节点分割成两个子节点来存储一个点集。每个节点表示一个范围&#xff0c;并且存储该范围内所有点的最小和最大值。范…...

005.HCIA 传输层

传输层定义了主机应用程序之间端到端的连通性。传输层中最为常见的两个协议分别是传输控制协议TCP (Transmission Control Protocol)和用户数据包协议UDP (User Datagram Protocol)。 1、相关概念 a. 传输层的端口 端口范围&#xff1a;0-65535 知名端口&#xff1a;0-1023&…...

LLM之RAG实战(八)| 使用Neo4j和LlamaIndex实现多模态RAG

人工智能和大型语言模型领域正在迅速发展。一年前&#xff0c;没有人使用LLM来提高生产力。时至今日&#xff0c;很难想象我们大多数人或多或少都在使用LLM提供服务&#xff0c;从个人助手到文生图场景。由于大量的研究和兴趣&#xff0c;LLM每天都在变得越来越好、越来越聪明。…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

BLEU评分:机器翻译质量评估的黄金标准

BLEU评分&#xff1a;机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域&#xff0c;衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标&#xff0c;自2002年由IBM的Kishore Papineni等人提出以来&#xff0c;…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

Chrome 浏览器前端与客户端双向通信实战

Chrome 前端&#xff08;即页面 JS / Web UI&#xff09;与客户端&#xff08;C 后端&#xff09;的交互机制&#xff0c;是 Chromium 架构中非常核心的一环。下面我将按常见场景&#xff0c;从通道、流程、技术栈几个角度做一套完整的分析&#xff0c;特别适合你这种在分析和改…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...

数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 原创笔记&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 上一篇&#xff1a;《数据结构第4章 数组和广义表》…...

Python常用模块:time、os、shutil与flask初探

一、Flask初探 & PyCharm终端配置 目的: 快速搭建小型Web服务器以提供数据。 工具: 第三方Web框架 Flask (需 pip install flask 安装)。 安装 Flask: 建议: 使用 PyCharm 内置的 Terminal (模拟命令行) 进行安装,避免频繁切换。 PyCharm Terminal 配置建议: 打开 Py…...

raid存储技术

1. 存储技术概念 数据存储架构是对数据存储方式、存储设备及相关组件的组织和规划&#xff0c;涵盖存储系统的布局、数据存储策略等&#xff0c;它明确数据如何存储、管理与访问&#xff0c;为数据的安全、高效使用提供支撑。 由计算机中一组存储设备、控制部件和管理信息调度的…...

Spring AI中使用ChatMemory实现会话记忆功能

文章目录 1、需求2、ChatMemory中消息的存储位置3、实现步骤1、引入依赖2、配置Spring AI3、配置chatmemory4、java层传递conversaionId 4、验证5、完整代码6、参考文档 1、需求 我们知道大型语言模型 &#xff08;LLM&#xff09; 是无状态的&#xff0c;这就意味着他们不会保…...