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

Stream 过滤后修改元素,却意外修改原列表

1. 问题重现

List<StringBuffer> list = Lists.newArrayList(new StringBuffer("a"),new StringBuffer("b")
);
List<StringBuffer> filterList = list.stream().filter(v -> "a".equalsIgnoreCase(v.toString())).collect(Collectors.toList());for (StringBuffer v : filterList) {v.append("b");
}System.out.println(list); // 输出:[ab, b]

在这里插入图片描述
看似只是想处理过滤结果集,但是最终打印原 list 却变成 [ab, b]。为什么会这样?

2. 原因分析

这是因为引用传递导致原始数据被修改,Java 对象是通过引用在集合中传递的,Stream.filter 和 collect 并不会自动复制对象,只是把满足条件的对象引用留下来形成新的列表。结果导致filter 后的 filterList 和原 list 指向的是同一个 StringBuffer 实例。

3. 正确做法

3.1 方案一:深拷贝元素再修改

如果你只想处理过滤后的数据,避免污染原列表状态,需要对每个元素执行深拷贝(Clone 或构造新实例)。

List<StringBuffer> safeList = list.stream().filter(v -> "a".equalsIgnoreCase(v.toString())).map(v -> new StringBuffer(v.toString())).collect(Collectors.toList());for (StringBuffer v : safeList) {v.append("b");
}
System.out.println(list);      // [a, b]
System.out.println(safeList);  // [ab]
3.2 方案二:手动 new 集合再操作
List<StringBuffer> safeList = new ArrayList<>();
for (StringBuffer sb : list) {if ("a".equalsIgnoreCase(sb.toString())) {safeList.add(new StringBuffer(sb.toString()));}
}
3.3 方案三:如果只是想批量修改原列表元素

如果业务是要修改原列表的对象状态,用 forEach 或 replaceAll 更清晰。

//  forEach 
list.replaceAll(sb -> {if ("a".equalsIgnoreCase(sb.toString())) {sb.append("b");}return sb;
});// replaceAll
list.stream().filter(v -> "a".equalsIgnoreCase(v.toString())).forEach(v -> v.append("b"));

4. 补充

Stream 的行为应尽量无副作用(no side-effects),peek 操作主要用于调试而非修改状态 。
虽然技术上可以用 .peek(u -> u.setXxx(…)) 修改对象,但这违反函数式编程设计原则,应尽量避免。

http://www.dtcms.com/a/312410.html

相关文章:

  • Swift 运算符
  • 【Django】-9- 单元测试和集成测试(上)
  • Android 之 蓝牙通信(4.0 BLE)
  • Redis+Lua的分布式限流器
  • C++编译过程与GDB调试段错误和死锁问题
  • 北邮:LLM强化学习架构Graph-R1
  • C++-二叉树OJ题
  • 【反转字符串中的单词】
  • 从零开始设计一个分布式KV存储:基于Raft的协程化实现
  • 吴恩达【prompt提示词工程】学习笔记
  • C# async await 实现机制详解
  • GR-3:字节跳动推出40亿参数通用机器人大模型,精确操作提升250%,开启具身智能新纪元!
  • FasrCGI
  • ospf笔记和 综合实验册
  • visual studio code 怎样将主题修改成亮色,并且配置中文界面
  • zookeeper常见命令和常见应用
  • MySQL——运维篇
  • K8S部署ELK(五):集成Kibana实现日志可视化
  • MySQL面试题及详细答案 155道(021-040)
  • 使用Database Navigator插件进行连接sqlite报错invalid or incomplete database
  • 2025年开关电源行业深度解析:从传统应用到新兴赛道的黄金赛道
  • MVC 发布
  • 代码随想录day53图论4
  • trace-cmd记录线程被中断打断的时间
  • 笔试——Day27
  • RabbitMQ面试精讲 Day 10:消息追踪与幂等性保证
  • spring-ai-alibaba 之 graph 槽点
  • 【设计模式】4.装饰器模式
  • 2025-0803学习记录21——地表分类产品的精度验证
  • Github怎么只下载某个目录文件?(Git稀疏检出、GitZip for Github插件、在线工具DownGit)Github下载目录