结论:用 collection.removeif 删除符合条件的元素更安全简洁,但 predicate 不可抛异常或修改集合;for-each 中直接 remove 会触发 concurrentmodificationexception,因底层 iterator 检测到结构不一致;正确做法仅 iterator.remove() 或 removeif()。

直接说结论:用 Collection.removeIf 删除符合条件的元素,比手动遍历 + Iterator.remove() 更安全、更简洁,但必须确保传入的 Predicate 不抛异常、不修改集合本身,否则会出 ConcurrentModificationException 或逻辑错乱。
为什么不能在 for-each 循环里调用 remove()
这是最常踩的坑:写 for (String s : list) { if (s.isEmpty()) list.remove(s); } 会直接触发 ConcurrentModificationException。因为 for-each 底层用的是 Iterator,而 list.remove() 是结构修改操作,迭代器检测到不一致就炸。
- 正确做法只有两种:用
Iterator.remove(),或用removeIf() -
removeIf()内部就是封装了安全的迭代 + 删除逻辑,你不用管底层怎么同步状态 - 别试图用
list.subList().clear()或倒序 for 循环“绕过”——可读性差,且对并发场景无效
removeIf 的 Predicate 里能做什么?
removeIf 接收一个 Predicate super E>,它只该做一件事:返回 true 表示“这个元素要被删”。任何副作用都危险。
- ✅ 允许:纯判断,比如
s -> s == null || s.trim().length() == 0 - ❌ 禁止:在 lambda 里调用
list.add()、map.put(),甚至System.out.println()(虽然不崩,但违背契约) - ⚠️ 特别注意:如果
Predicate调用了可能抛RuntimeException的方法(如s.length()而s为null),整个删除会中断,已删部分不可回滚
ArrayList vs LinkedList 下 removeIf 性能差异大吗?
差异明显,但和你想的可能相反:对 ArrayList,removeIf 是 O(n) 时间 + O(n) 空间(内部用位图标记+批量移动);对 LinkedList,是 O(n) 时间但每次删除都要寻址,实际更慢。
立即学习“Java免费学习笔记(深入)”;
- 如果你频繁删中间元素,且集合很大,
ArrayList.removeIf反而比手写Iterator略快(JVM 优化过批量移动) -
LinkedList.removeIf没有优势,真要高频删查,换ArrayDeque或考虑是否该用别的数据结构 - 别为了“看起来更函数式”强行用
removeIf处理超大数据集——先确认 GC 压力和暂停时间是否可接受
最易被忽略的一点:removeIf 不支持中断或分批处理。一旦开始,就得跑完全部元素,也没法知道删了多少个(除非自己计数)。如果业务需要“删前 10 个匹配项”或“删到内存告警就停”,就得退回去用手动 Iterator 控制流程。









