replaceAll() 要求 UnaryOperator 必须返回同类型新值,不能仅就地修改;需处理 null、保持类型一致、避免副作用,且不支持跳过元素。

replaceAll() 为什么不能直接传 lambda 修改原对象字段
因为 replaceAll() 接收的是 UnaryOperator,它要求函数返回一个新值(类型必须是 T),而不是“就地修改”。如果你写 list.replaceAll(x -> { x.setName("new"); return x; }),看似改了,但前提是 x 是可变对象且你返回的是同一个引用——这容易误以为在“更新”,实则只是借用返回值完成赋值。真正安全的做法是返回一个**新构造的对象**或明确的替换值。
常见错误现象:NullPointerException(当 list 含 null 且 operator 未处理)、类型不匹配(比如想返回 String 但 list 是 List)。
- operator 必须保持输入输出类型一致:输入
Integer就得返回Integer,不能返回int或String - 如果 list 元素为
null,operator 会收到null,需主动判空,否则 NPE - 该方法会直接修改原 list,不可逆;如需保留原始数据,先
new ArrayList(original)
用 Lambda 处理字符串批量清洗的典型写法
比如把 List 中每个元素去首尾空格、转小写、再过滤掉空字符串(注意:replaceAll() 不负责过滤,只替换,空字符串仍会保留):
list.replaceAll(s -> s == null ? null : s.trim().toLowerCase());
这里的关键是:返回值类型必须仍是 String,所以不能用 Objects.requireNonNullElse(s, "").trim() 然后返回空串——那没问题;但若写成 s.trim().isEmpty() ? null : s.trim(),就可能引入 null,后续遍历时要小心。
- 不要试图在 lambda 里做条件跳过(如 “跳过 null”)——
replaceAll()没有 skip 机制,null 也会被传入 operator - 性能上无额外开销,它就是 for 循环 + set(i, result),比手写 for 更简洁,但和 stream.map().collect() 比略快(少建中间集合)
- Java 8+ 可用,Android 需 API 24+(即 Java 8 支持开启后才可用)
配合 record 或不可变类时的正确替换模式
如果你的 list 是 List,而 Person 是 record 或 final 字段的类,就不能“改字段”,只能“换对象”。这时 replaceAll() 才真正发挥语义优势:
list.replaceAll(p -> new Person(p.name().toUpperCase(), p.age() + 1));
注意:record 的 getter 名是 name() 而非 getName(),别写错函数名;如果用 Lombok @Data 的普通类,则仍用 p.getName()。
- 务必确认构造逻辑覆盖所有必要字段,漏掉字段会导致默认值(如 int=0、String=null)
- 如果构造开销大(如含数据库查询),别放在这里——
replaceAll()是同步阻塞调用 - 泛型擦除不影响运行时行为,但 IDE 可能对嵌套泛型(如
List)提示弱,建议拆解验证- >
和 Collections.replaceAll() 容易混淆的点
Collections.replaceAll() 是静态方法,功能完全不同:它把 list 中所有等于某旧值的元素替换成新值(基于 equals()),例如 Collections.replaceAll(list, "old", "new")。而 List.replaceAll() 是实例方法,逐个调用 operator,跟值是否相等无关。
- 别把
Collections.replaceAll(list, null, "default")和list.replaceAll(x -> x == null ? "default" : x)当作等价——前者只替换字面值为null的元素,后者还能做任意计算 - 前者在内部用 for + equals 判断,后者用 for + 函数调用,二者时间复杂度都是 O(n),但后者灵活性高得多
- 如果真想“把所有 null 替换成默认值”,用
replaceAll()更直接;想“把所有 'ERROR' 换成 'OK'”,用Collections.replaceAll()更语义清晰
实际用的时候,最常被忽略的是 null 处理和返回类型一致性——写完 lambda 先盯一眼泛型参数和返回表达式,再扫一眼 list 是否可能含 null。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











