Stream特性(踩坑):惰性执行、不修改原始数据源

在日常开发中,Stream API 提供了一种高效且易于使用的工具集来处理集合数据。

本文主要讲解 Stream 的两个特性:惰性执行不修改原始数据源

为什么说这两个、而不讲下其他的特性呢?主要是因为在开发中如果忽略这两个特性的话,使用 Stream 写出来的代码就可能 Bug 多多啊,因此在这里特别强调下。

1.惰性执行

1.1.说明

惰性执行 意味着 Stream 的中间操作 (intermediate operations,如filter, map)不会立即执行,而是在遇到终止操作 (terminal operations,如forEach, collect)时才会触发。

1.2.反例

考虑以下代码:

java 复制代码
List<String> words = Arrays.asList("apple", "banana", "cherry");
words.stream()
     .filter(word -> {
         System.out.println("Filtering: " + word);
         return word.startsWith("a");
     });

以上代码执行后并不会有打印输出,这是因为尽管调用了中间操作 filter,但是 filter 后并没有调用终止操作的方法。

1.3.正确使用

应该习惯性地在流操作的最后,都调用一个终止操作

例如:

java 复制代码
words.stream()
     .filter(word -> word.startsWith("a"))
     .forEach(System.out::println);

1.3.1.如何区分中间操作和终止操作

这其实很简单,如果一个方法的返回结果为一个新的流 (Stream),那么它是中间操作,否则就是终止操作。

2.不修改原始数据源

2.1.说明

Stream 的操作并不会改变原始数据,Stream 操作都是基于原始数据创建新的结果

2.2.反例

假设有如下代码:

java 复制代码
List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3));
numbers.stream()
       .map(n -> n * 2)
       .collect(Collectors.toList());

System.out.println(numbers); // 输出 [1, 2, 3]

可能有人会错误地认为,Stream 操作执行后,numbers列表的元素会发生改变,然后就把numbers作为计算后的结果接着往下执行逻辑。

但实际上,Stream 操作的结果是生成了一个新的集合,而原始的集合numbers保持不变。

2.3.正确使用

应该用一个新对象接收 Stream 操作的结果,后续如果需要使用计算后的结果,使用的应该是这个新的对象,而不是原始的数据集合。

java 复制代码
List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3));
List<Integer> doubledNumbers = numbers.stream()
                                      .map(n -> n * 2)
                                      .collect(Collectors.toList());
System.out.println(doubledNumbers); // 输出 [2, 4, 6]

又或者,可以直接用 Stream 操作的结果覆盖掉原始的数据对象。

java 复制代码
List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3));
numbers = numbers.stream()
              .map(n -> n * 2)
              .collect(Collectors.toList());
System.out.println(numbers); // 输出 [2, 4, 6]

如果有帮助的话,可以点个赞支持一下嘛🙏

相关推荐
毕设源码-邱学长4 小时前
【开题答辩全过程】以 基于JavaWeb医院住院信息管理系统的设计与实现为例,包含答辩的问题和答案
java·eclipse
q***47184 小时前
解决 Tomcat 跨域问题 - Tomcat 配置静态文件和 Java Web 服务(Spring MVC Springboot)同时允许跨域
java·前端·spring
青云交4 小时前
Java 大视界 -- Java 大数据机器学习模型在自然语言生成中的可控性研究与应用实战
java·机器学习·强化学习·模型融合·java 大数据·可控性·自然语言生成
小光学长4 小时前
基于Web的课前问题导入系统pn8lj4ii(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
java·前端·数据库
小何开发4 小时前
Springboot-WebService 服务端发布与客户端调用
java·spring boot·后端
今天的砖很烫4 小时前
ThreadLocal 结构设计的精妙之处
java·开发语言
q***46524 小时前
Spring Boot 整合 Keycloak
java·spring boot·后端
LSL666_4 小时前
spring多配置文件
java·服务器·前端·spring
jakeswang4 小时前
JDK 25 重大兼容性 Bug
java
麦麦鸡腿堡4 小时前
Java_HashMap底层机制与原码解读
java·开发语言·jvm