Java 8 中的 Stream API,用于处理集合数据
Java 8 引入了 Stream API,使得处理集合数据变得更加简洁和高效。Stream API 允许开发者以声明式编程风格操作数据集合,而不是使用传统的迭代和条件语句。
一、基本概念
1.1 什么是 Stream
Stream 是 Java 8 中的一个新抽象,它允许对集合数据执行各种复杂的操作,例如过滤、映射、规约、收集等。Stream 不存储数据,而是从集合或其他数据源(如数组、I/O channel 等)中获取数据并进行操作。
Stream 的主要特点包括:
- 无存储:Stream 不存储数据,只是对数据进行操作。
 - 函数式编程:使用 lambda 表达式进行操作,使代码更简洁。
 - 延迟执行:Stream 操作是懒加载的,只有在需要结果时才会执行。
 - 可组合性:多个 Stream 操作可以连成一串操作链,形成一系列的转换。
 
1.2 Stream 的生命周期
Stream 的操作可以分为三类:
- 源:创建 Stream 的数据源,例如集合、数组或 I/O channel。
 - 中间操作:返回新的 Stream 的操作,例如过滤、映射。
 - 终端操作:产生结果或副作用的操作,例如收集、计算。
 
一个 Stream 的生命周期可以简单描述为:
- 创建 Stream。
 - 中间操作。
 - 终端操作。
 
二、Stream API 的基本操作
2.1 创建 Stream
Stream 可以通过以下几种方式创建:
- 从集合:
 
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
 
- 从数组:
 
String[] array = {"a", "b", "c"};
Stream<String> stream = Arrays.stream(array);
 
- 从值:
 
Stream<String> stream = Stream.of("a", "b", "c");
 
- 从文件:
 
Stream<String> stream = Files.lines(Paths.get("path/to/file.txt"));
 
2.2 中间操作
中间操作返回一个新的 Stream,它们是延迟执行的,只有在终端操作执行时才会实际进行计算。常用的中间操作包括:
2.2.1 filter
 
filter 用于对 Stream 中的元素进行过滤,只保留满足条件的元素。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0);
 
2.2.2 map
 
map 用于将 Stream 中的每个元素映射到另一个元素。
List<String> words = Arrays.asList("Java", "Stream", "API");
Stream<Integer> wordLengths = words.stream().map(String::length);
 
2.2.3 flatMap
 
flatMap 用于将 Stream 中的每个元素映射到一个新的 Stream,并将这些新 Stream 合并成一个 Stream。
List<List<String>> listOfLists = Arrays.asList(Arrays.asList("a", "b"), Arrays.asList("c", "d"));
Stream<String> flatStream = listOfLists.stream().flatMap(Collection::stream);
 
2.2.4 distinct
 
distinct 用于去除 Stream 中的重复元素。
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
Stream<Integer> distinctNumbers = numbers.stream().distinct();
 
2.2.5 sorted
 
sorted 用于对 Stream 中的元素进行排序,可以传递一个比较器。
List<String> words = Arrays.asList("Java", "Stream", "API");
Stream<String> sortedWords = words.stream().sorted();
 
2.3 终端操作
终端操作会触发 Stream 的计算,并生成结果或副作用。常用的终端操作包括:
2.3.1 forEach
 
forEach 用于对 Stream 中的每个元素执行一个动作。
List<String> words = Arrays.asList("Java", "Stream", "API");
words.stream().forEach(System.out::println);
 
2.3.2 toArray
 
toArray 用于将 Stream 中的元素收集到一个数组中。
List<String> words = Arrays.asList("Java", "Stream", "API");
String[] array = words.stream().toArray(String[]::new);
 
2.3.3 reduce
 
reduce 用于将 Stream 中的元素通过一个关联函数组合起来,生成一个值。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().reduce(0, Integer::sum);
 
2.3.4 collect
 
collect 用于将 Stream 中的元素收集到一个容器中,例如 List、Set 或 Map。
List<String> words = Arrays.asList("Java", "Stream", "API");
List<String> upperCaseWords = words.stream().map(String::toUpperCase).collect(Collectors.toList());
 
2.3.5 count
 
count 用于返回 Stream 中的元素数量。
List<String> words = Arrays.asList("Java", "Stream", "API");
long count = words.stream().count();
 
2.3.6 findFirst 和 findAny
 
findFirst 用于返回 Stream 中的第一个元素(如果存在)。
List<String> words = Arrays.asList("Java", "Stream", "API");
Optional<String> first = words.stream().findFirst();
 
findAny 用于返回 Stream 中的任意一个元素(如果存在),常用于并行流。
List<String> words = Arrays.asList("Java", "Stream", "API");
Optional<String> any = words.stream().findAny();
 
2.3.7 anyMatch、allMatch 和 noneMatch
 
这三个操作用于检查 Stream 中是否有任意、所有或没有元素满足指定的条件。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean anyEven = numbers.stream().anyMatch(n -> n % 2 == 0);
boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);
boolean noneNegative = numbers.stream().noneMatch(n -> n < 0);
 
三、并行流
Java 8 提供了并行流,可以充分利用多核处理器的优势。只需调用 parallelStream 方法即可创建一个并行流。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.parallelStream().reduce(0, Integer::sum);
 
并行流通过将数据分成多个子流,并在不同的 CPU 核心上并行处理这些子流,然后再合并结果,来提高处理速度。需要注意的是,并行流适合于无状态和无副作用的操作,使用时需小心处理共享变量和同步问题。
四、Stream API 的最佳实践
4.1 使用 Lambda 表达式
Stream API 通常与 lambda 表达式一起使用,使代码更加简洁和易读。例如:
List<String> words = Arrays.asList("Java", "Stream", "API");
List<String> upperCaseWords = words.stream().map(word -> word.toUpperCase()).collect(Collectors.toList());
 
4.2 避免使用修改状态的中间操作
Stream 操作应该是无副作用的,即不应修改外部状态。以下示例展示了一个错误的用法:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> results = new ArrayList<>();
numbers.stream().forEach(n -> results.add(n * 2));  // 这样做是错误的
 
正确的做法是使用终端操作 collect:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> results = numbers.stream().map(n -> n * 2).collect(Collectors.toList());
 
4.3 利用方法引用
方法引用可以使代码更加简洁。例如,使用方法引用替代 lambda 表达式:
List<String> words = Arrays.asList("Java", "Stream", "API");
List<String> upperCaseWords = words.stream().map(String::toUpperCase).collect(Collectors.toList());
 
4.4 避免使用并行流进行小任务
并行流在处理大量数据或复杂计算时非常高效,但对于小任务,启动并行计算的开销可能会大于收益。因此,在数据量较小或计算较简单的情况下,优先使用顺序流。
4.5 避免在终端操作之前调用 findAny
 
在终端操作之前调用 findAny 会导致流的中间操作链被截断,进而无法正确执行后续的操作。例如:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> result = numbers.stream().filter(n -> n % 2 == 0).findAny(); // 这样做会中断流
 
应将 findAny 用作终端操作:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> result = numbers.stream().filter(n -> n % 2 == 0).findAny();
 
4.6 使用 collect 进行结果收集
 
collect 是一个强大的终端操作,可以将流中的元素收集到各种容器中。例如,收集到 List:
List<String> words = Arrays.asList("Java", "Stream", "API");
List<String> wordList = words.stream().collect(Collectors.toList());
 
4.7 使用 Collectors 进行复杂收集操作
 
Collectors 提供了多种收集器,可以进行复杂的结果收集。例如,收集到 Map:
List<String> words = Arrays.asList("Java", "Stream", "API");
Map<Integer, List<String>> wordLengthMap = words.stream().collect(Collectors.groupingBy(String::length));
 
4.8 使用 Optional 处理可能的空值
 
Stream API 中的某些终端操作会返回 Optional,例如 findFirst、findAny。使用 Optional 可以避免空指针异常:
List<String> words = Arrays.asList("Java", "Stream", "API");
Optional<String> firstWord = words.stream().findFirst();
firstWord.ifPresent(System.out::println);
 
Java 8 的 Stream API 为集合数据的处理提供了一种高效、简洁的方式。通过理解和掌握 Stream 的基本概念、常用操作以及最佳实践,可以大大提高 Java 开发的生产力和代码质量。
Stream API 不仅支持顺序流,还支持并行流,使得在多核环境下处理大量数据变得更加高效。在实际开发中,合理使用 Stream API 可以显著提升代码的可读性和稳定性。
黑马程序员免费预约咨询

相关文章:
Java 8 中的 Stream API,用于处理集合数据
Java 8 引入了 Stream API,使得处理集合数据变得更加简洁和高效。Stream API 允许开发者以声明式编程风格操作数据集合,而不是使用传统的迭代和条件语句。 一、基本概念 1.1 什么是 Stream Stream 是 Java 8 中的一个新抽象,它允许对集合数…...
106、python-第四阶段-3-设计模式-单例模式
不是单例类,如下: class StrTools():pass str1StrTools() str2StrTools() print(str1) print(str2) 运用单例,先创建一个test.py class StrTools():pass str1StrTools()然后创建一个hello.py,在这个文件中引用test.py中的对象&a…...
【猫狗识别系统】图像识别Python+TensorFlow+卷积神经网络算法+人工智能深度学习
猫狗识别系统。通过TensorFlow搭建MobileNetV2轻量级卷积神经算法网络模型,通过对猫狗的图片数据集进行训练,得到一个进度较高的H5格式的模型文件。然后使用Django框架搭建了一个Web网页端可视化操作界面。实现用户上传一张图片识别其名称。 一、前言 …...
记录汇川:红绿灯与HMI-ST
项目要求: 子程序: 子程序: 实际动作如下: 红绿灯与HMI-ST...
已解决java.nio.charset.CoderMalfunctionError: 编码器故障错误的正确解决方法,亲测有效!!!
已解决java.nio.charset.CoderMalfunctionError: 编码器故障错误的正确解决方法,亲测有效!!! 亲测有效 报错问题解决思路解决方法1. 检查和清理输入数据2. 选择正确的字符集3. 处理异常情况4. 更新Java版本或库5. 检查第三方库的依…...
Linux 中常用的设置、工具和操作
1.设置固定的ip地址步骤 1.1 添加IPADDR“所设置的固定ip地址” TYPE"Ethernet" PROXY_METHOD"none" BROWSER_ONLY"no" BOOTPROTO"static" DEFROUTE"yes" IPV4_FAILURE_FATAL"no" IPV6INIT"yes" IPV6…...
[论文笔记]AIOS: LLM Agent Operating System
引言 这是一篇有意思的论文AIOS: LLM Agent Operating System,把LLM智能体(代理)看成是操作系统。 基于大语言模型(LLMs)的智能代理的集成和部署过程中存在着许多挑战,其中问题包括代理请求在LLM上的次优调度和资源分配,代理和LLM之间在交互…...
2024全国高考作文题解读(文心一言 4.0版本)
新课标I卷 阅读下面的材料,根据要求写作。(60分) 随着互联网的普及、人工智能的应用,越来越多的问题能很快得到答案。那么,我们的问题是否会越来越少? 以上材料引发了你怎样的联想和思考?请写…...
【功能超全】基于OpenCV车牌识别停车场管理系统软件开发【含python源码+PyqtUI界面+功能详解】-车牌识别python 深度学习实战项目
车牌识别基础功能演示 摘要:车牌识别系统(Vehicle License Plate Recognition,VLPR) 是指能够检测到受监控路面的车辆并自动提取车辆牌照信息(含汉字字符、英文字母、阿拉伯数字及号牌颜色)进行处理的技术。车牌识别是现代智能交通…...
TESSENT2024.1安装
一、安装过程参考Calibre安装过程(此处省略,不再赘述) 二、安装license管理器: SiemensLicenseServer_v2.2.1.0_Lnx64_x86-64.bin 三、Patch补丁: tessent安装目录和license管理安装目录,执行FlexNetLic…...
【机器学习】原理与应用场景 Python代码展现
机器学习:原理、应用与实例深度解析 引言一、机器学习的基本原理二、机器学习的应用范围三、机器学习实例解析四、机器学习部分讲解五、机器学习的挑战与未来 引言 随着大数据和计算能力的飞速发展,机器学习(Machine Learning, ML࿰…...
Python怎么循环计数:深入解析与实践
Python怎么循环计数:深入解析与实践 在Python编程中,循环计数是一项基础且重要的技能。无论是处理列表、遍历文件,还是执行重复任务,循环计数都发挥着不可或缺的作用。本文将从四个方面、五个方面、六个方面和七个方面详细阐述Py…...
Facebook企业户 | Facebook公共主页经营
Facebook作为社交媒体巨头,拥有庞大的用户基数,因此,有效经营公共主页是获取持续流量、提升客户信任度和粘性、促进产品或服务销售与转化的关键。要优化Facebook主页,关注以下几点: 1、参与度是关键指标:因…...
排序数组 ---- 分治-归并
题目链接 题目: 分析: 用这道题来回顾一下归并排序的思想找到中间结点, 将数组分成两半, 运用递归的思想, 继续对一半进行分半, 分到最后剩一个元素, 再将左右数组合并, 合并两个有序数组, 是先分解, 再合并的过程在合并两个有序数组时, 需要一个额外的数组来记录, 为了避免每…...
【红黑树变色+旋转】
文章目录 一. 红黑树规则二. 情况一叔叔存在且为红情况二.变色旋旋 一. 红黑树规则 对于红黑树,进行变色旋转处理,终究都是为了维持颜色以下几条规则,只有颜色和规则维持住了,红黑树就维持住了最长路径的长度不超过最短路径的两倍…...
pytorch 使用tensor混合:进行index操作
(Pdb) tmp torch.randn(3,5) (Pdb) indx torch.tensor([1,0]).long() (Pdb) temp(indx) *** NameError: name ‘temp’ is not defined (Pdb) tmp(indx) *** TypeError: ‘Tensor’ object is not callable (Pdb) tmp[indx] tensor([[ 0.1633, 0.9389, 1.2806, -0.2525, 0.28…...
Threejs(WebGL)绘制线段优化:Shader修改gl.LINES模式为gl.LINE_STRIP
目录 背景 思路 Threejs实现 记录每条线的点数 封装原始裁剪索引数据 封装合并几何体的缓冲数据:由裁剪索引组成的 IntArray 守住该有的线段! 修改顶点着色器 修改片元着色器 完整代码 WebGL实现类似功能(简易版,便于测…...
继承-进阶
父子类成员共享 普通成员对象/父子间不共享, 成员独立 函数成员共享(函数不存储在对象中) 子类由两部分构成:父类中继承的成员和子类中新定义成员 继承方式 子类中存在父类private成员但不可直接访问(及时在类中&am…...
探索k8s集群的配置资源(secret和configmap)
目录 ConfigMap ConfigMap(主要是将配置目录或者文件挂载到k8s里面使用) 与Secret类似,区别在于ConfigMap保存的是不需要加密配置的信息。(例如:配置文件) ConfigMap 功能在 Kubernetes1.2 版本中引入&…...
如何设置vue3项目中默认的背景为白色
方法1:通过CSS全局样式 在全局CSS文件中设置: 如果你的项目中有全局的CSS文件(如App.vue或专门的CSS文件),你可以直接设置body或html标签的背景颜色。 在src/assets文件夹中(或者任何你存放CSS文件的地方&a…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
