Java stream流的避坑指南

在使用Java Stream API时,虽然它提供了强大的功能来简化集合操作,但也存在一些常见的“坑”需要注意。以下是详细的避坑指南:

1. Stream的不可重用性

  • 问题:Stream一旦被消费(如调用forEachcollect等终端操作),就不能再次使用。
  • 解决方案:如果需要多次操作同一个数据源,可以重新创建Stream,或者将Stream的结果保存到集合中。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = numbers.stream();
stream.forEach(System.out::println); // 第一次消费
stream.forEach(System.out::println); // 抛出IllegalStateException

2. 并行流的线程安全问题

  • 问题:并行流(parallelStream)在多线程环境下可能会引发线程安全问题,尤其是在共享可变状态时。
  • 解决方案:避免在并行流中使用共享的可变状态,或者使用线程安全的集合(如ConcurrentHashMap)。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> result = new ArrayList<>();
numbers.parallelStream().forEach(result::add); // 线程不安全

3. Stream的延迟执行

  • 问题:Stream的中间操作(如filtermap)是延迟执行的,只有在终端操作(如collectforEach)调用时才会真正执行。
  • 解决方案:确保在终端操作之前完成所有中间操作,避免在中间操作中引入副作用。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = numbers.stream().filter(n -> {System.out.println("Filtering: " + n);return n > 2;
}); // 不会立即执行
stream.forEach(System.out::println); // 执行过滤和输出

4. Stream的性能问题

  • 问题:Stream的操作可能会带来额外的性能开销,尤其是在数据量较小的情况下。
  • 解决方案:对于简单的操作,使用传统的循环可能更高效。对于大数据集,Stream的并行流可以提高性能。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 传统循环
for (int n : numbers) {if (n > 2) {System.out.println(n);}
}
// Stream
numbers.stream().filter(n -> n > 2).forEach(System.out::println);

5. Stream的空指针问题

  • 问题:如果Stream的元素为null,可能会引发NullPointerException
  • 解决方案:在操作Stream之前,确保元素不为null,或者使用Optional来处理可能的null值。
List<String> list = Arrays.asList("a", "b", null, "c");
list.stream().filter(Objects::nonNull).forEach(System.out::println);

6. Stream的排序问题

  • 问题sorted操作可能会改变Stream的顺序,尤其是在并行流中。
  • 解决方案:确保在排序操作之前完成所有中间操作,或者使用Comparator来明确排序规则。
List<Integer> numbers = Arrays.asList(5, 3, 1, 4, 2);
numbers.stream().sorted().forEach(System.out::println); // 1, 2, 3, 4, 5

7. Stream的无限流问题

  • 问题Stream.generateStream.iterate可以创建无限流,如果不加以限制,可能会导致程序无法终止。
  • 解决方案:使用limit来限制流的大小,或者使用takeWhile来在满足条件时终止流。
Stream.generate(Math::random).limit(10).forEach(System.out::println);

8. Stream的副作用

  • 问题:在Stream操作中引入副作用(如修改外部变量)可能会导致不可预期的行为。
  • 解决方案:尽量避免在Stream操作中引入副作用,使用纯函数式操作。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = 0;
numbers.stream().forEach(n -> sum += n); // 不推荐
int total = numbers.stream().reduce(0, Integer::sum); // 推荐

9. Stream的flatMap使用

  • 问题flatMap用于将多个流合并为一个流,但如果使用不当,可能会导致性能问题或逻辑错误。
  • 解决方案:确保flatMap中的映射函数返回的是流,并且流的元素类型正确。
List<List<Integer>> nestedList = Arrays.asList(Arrays.asList(1, 2),Arrays.asList(3, 4),Arrays.asList(5, 6)
);
List<Integer> flatList = nestedList.stream().flatMap(List::stream).collect(Collectors.toList()); // [1, 2, 3, 4, 5, 6]

10. Stream的reduce操作

  • 问题reduce操作可能会因为初始值或累加器的使用不当而导致错误。
  • 解决方案:确保初始值与累加器的类型匹配,并且累加器函数是结合性的。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().reduce(0, Integer::sum); // 正确

总结

Java Stream API 提供了强大的功能,但也需要谨慎使用。理解Stream的特性和潜在问题,可以帮助我们避免常见的陷阱,编写出高效、安全的代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/69150.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

对于RocksDB和LSM Tree的一些理解

LSM Tree的读写过程 HBase、LevelDB&#xff0c;rocksDB&#xff08;是一个引擎&#xff09;底层的数据结构是LSM Tree适合写多读少的场景&#xff0c;都是追加写入内存中的MemTable&#xff0c;写入一条删除&#xff08;或修改&#xff09;标记&#xff0c;而不用去访问实际的…

偏差(Bias)和方差(Variance)

在机器学习中&#xff0c;偏差&#xff08;Bias&#xff09;和方差&#xff08;Variance&#xff09;是模型预测误差的两个主要组成部分&#xff0c;它们描述了模型在训练和预测过程中可能出现的两种不同类型的错误。 偏差&#xff08;Bias&#xff09; 偏差指的是模型在训练…

枚举与模拟 练习

练习题基于《C/C程序设计竞赛真题实战特训教程&#xff08;图解版&#xff09;》 目录 1.1 卡片 题目描述 代码实现 题解笔记 总评 注意点 重点解释 1.2 回文日期 题目描述 输入描述 输出描述 代码实现 题解笔记 总评 注意点 重点解释 1.1 卡片 题目描述 小蓝…

99.17 金融难点通俗解释:归母净利润

目录 0. 承前1. 简述2. 比喻&#xff1a;小明家的小卖部2.1 第一步&#xff1a;计算收到的所有钱2.2 第二步&#xff1a;减去各种支出2.3 第三步&#xff1a;计算能带回家的钱 3. 生活中的例子3.1 好的经营情况3.2 一般的经营情况3.3 不好的经营情况 4. 小朋友要注意4.1 为什么…

[LeetCode] 字符串 I — 344#反转字符串 | 541#反转字符串II | 54K替换数字

字符串 基础知识344# 反转字符串541# 反转字符串II54K 替换数字 基础知识 字符串的结尾&#xff1a;空终止字符00 char* name "hello"; // 字符串不可拓展&#xff08;由于是一个固定分配的内存块&#xff09;&#xff0c;有些地方必须加const char name2[5] {h,…

【深度学习|迁移学习】渐进式学习策略 (Progressive Learning Strategy)详述(一)

【深度学习|迁移学习】渐进式学习策略 (Progressive Learning Strategy)详述&#xff08;一&#xff09; 【深度学习|迁移学习】渐进式学习策略 (Progressive Learning Strategy)详述&#xff08;一&#xff09; 文章目录 【深度学习|迁移学习】渐进式学习策略 (Progressive L…

NIO 和 Netty 在 Spring Boot 中的集成与使用

Netty到底是个啥&#xff0c;有啥子作用 1. Netty 的本质&#xff1a;对 NIO 的封装 NIO 的原生问题&#xff1a; Java 的 NIO 提供了非阻塞 I/O 和多路复用机制&#xff0c;但其使用较为复杂&#xff08;如 Selector、Channel、Buffer 的配置和管理&#xff09;。开发者需要自…

Linux第103步_了解I2C总线框架

了解Linux中的I2C总线框架为后面做I2C实验做准备&#xff0c;学驱动&#xff0c;就是学习框架&#xff0c;了解是必须的。 1、了解Linux下的I2C子系统中的相关数据结构 struct i2c_adapter { struct module *owner; unsigned int class; /* classes to allow probing for …

AAAI2024论文合集解读|Physics-Informed Representation and Learning Control and Risk

论文标题 Physics-Informed Representation and Learning: Control and Risk Quantification 物理信息表征与学习&#xff1a;控制与风险量化 论文链接 Physics-Informed Representation and Learning: Control and Risk Quantification论文下载 论文作者 Zhuoyuan Wang, …

Vue3组件重构实战:从Geeker-Admin拆解DataTable的最佳实践

一、前言 背景与动机 在当前的开发实践中&#xff0c;我们选择了开源项目 Geeker-Admin 作为前端框架的二次开发基础。其内置的 ProTable.vue 组件虽然提供了一定程度的开箱即用性&#xff0c;但在实际业务场景中逐渐暴露出设计上的局限性&#xff0c;尤其是其将 搜索条件表单…

【JavaEE进阶】Spring留言板实现

目录 &#x1f38d;预期结果 &#x1f340;前端代码 &#x1f384;约定前后端交互接口 &#x1f6a9;需求分析 &#x1f6a9;接口定义 &#x1f333;实现服务器端代码 &#x1f6a9;lombok介绍 &#x1f6a9;代码实现 &#x1f334;运行测试 &#x1f384;前端代码实…

HackTheBox靶机:Sightless;NodeJS模板注入漏洞,盲XSS跨站脚本攻击漏洞实战

HackTheBox靶机&#xff1a;Sightless 渗透过程1. 信息收集常规探测深入分析 2. 漏洞利用&#xff08;CVE-2022-0944&#xff09;3. 从Docker中提权4. 信息收集&#xff08;michael用户&#xff09;5. 漏洞利用 Froxlor6. 解密Keepass文件 漏洞分析SQLPad CVE-2022-0944 靶机介…

Ansible入门学习之基础元素介绍

一、Ansible目录结构介绍 1.通过rpm -ql ansible获取ansible所有文件存放的目录 有配置文件目录 /etc/ansible/ 执行文件目录 /usr/bin/ 其中 /etc/ansible/ 该文件目录的主要功能是 inventory主机信息配置&#xff0c;ansible工具功能配置。 ansible自身的配置文件…

【pytorch 】miniconda python3.11 环境安装pytorch

ubuntu24.04 miniconda python3.11 环境安装pytorch 组件:langgraph本身不需要有一些模型是需要的:python3.11环境:报错ModuleNotFoundError: No module named ‘torchaudio’ ModuleNotFoundError: No module named ‘torchaudio’File "/root/miniconda3/envs/05_ep_…

Antd React Form使用Radio嵌套多个Select和Input的处理

使用Antd React Form使用Radio会遇到嵌套多个Select和Input的处理&#xff0c;需要多层嵌套和处理默认事件和冒泡&#xff0c;具体实现过程直接上代码。 实现效果布局如下图 代码 <Formname"basic"form{form}labelWrap{...formItemLayoutSpan(5, 19)}onFinish{on…

11 蚂蚁链技术特性

概览 蚂蚁链通过引入P2P网络、共识算法、虚拟机、智能合约、密码学、数据存储等技术特性&#xff0c;构建一个稳定、高效、安全的图灵完备智能合约执行环境&#xff0c;提供账户的基本操作以及面向智能合约的功能调用。 区块结构 一个区块包含区块头和区块体&#xff0c;区块…

如何使用 pytest-html 创建自定义 HTML 测试报告

关注开源优测不迷路 大数据测试过程、策略及挑战 测试框架原理&#xff0c;构建成功的基石 在自动化测试工作之前&#xff0c;你应该知道的10条建议 在自动化测试中&#xff0c;重要的不是工具 测试 Python 代码对于提高代码质量、检测漏洞或意外行为至关重要。 但测试结果又该…

【华为OD-E卷 - VLAN资源池 100分(python、java、c++、js、c)】

【华为OD-E卷 - VLAN资源池 100分&#xff08;python、java、c、js、c&#xff09;】 题目 VLAN是一种对局域网设备进行逻辑划分的技术&#xff0c;为了标识不同的VLAN&#xff0c;引入VLAN ID(1-4094之间的整数)的概念。 定义一个VLAN ID的资源池(下称VLAN资源池)&#xff0…

【C++高并发服务器WebServer】-5:内存映射与进程通信

本文目录 一、内存映射与进程通信二、匿名映射与进程通信 一、内存映射与进程通信 内存映射Memory-mapped I/O指的是将磁盘文件的数据映射到内存&#xff0c;用户通过修改内存就能够修改磁盘文件&#xff0c;如下图所示&#xff08;进程地址空间指的是虚拟地址空间&#xff09…

使用vscode + Roo Code (prev. Roo Cline)+DeepSeek-R1使用一句话需求做了个实验

摘要 使用vscode、Roo Code和deepseek-reasoner进行了一个实验&#xff0c;尝试使用一句话需求来生成小红书封面图片。工具根据需求提供了详细的架构方案&#xff0c;包括技术栈选择、核心模块划分、目录结构建议等。然后&#xff0c;工具自动化地完成了开发和测试&#xff0c;…