Java集合遍历时应使用Iterator.remove()避免ConcurrentModificationException,因其同步更新内部状态;优先用removeIf()简化条件删除;多线程场景需换用CopyOnWriteArrayList或ConcurrentHashMap。

Java 集合遍历时用 Iterator 避免并发修改异常,核心不是“捕获异常”,而是从机制上防止触发 ConcurrentModificationException。这个异常本质是 fail-fast 机制的主动拦截——它不表示线程冲突,而是检测到集合结构被非法修改(即非 Iterator 自身调用的 remove)。只要用对方法,单线程下也能轻松避开。
必须用 Iterator.remove() 删除当前元素
这是最标准、最安全的做法。Iterator 的 remove() 方法会同步更新内部状态(如 expectedModCount),让后续 hasNext() 或 next() 校验通过。
- 调用前提:必须先执行一次
next(),拿到当前元素后才能调用remove() - 调用限制:每个
next()后最多调用一次remove();重复调用抛IllegalStateException - 不能在增强 for 循环中使用,因为拿不到 Iterator 实例
优先用 removeIf() 替代手动迭代
Java 8 起,Collection.removeIf(Predicate) 是更简洁、更不易出错的选择。它封装了安全迭代逻辑,底层仍调用 Iterator.remove(),但开发者无需管理游标。
- 一行代码完成条件删除,语义清晰:例如
list.removeIf(s -> s == null || s.trim().isEmpty()) - 适用于 ArrayList、LinkedList、HashSet、TreeSet 等所有标准集合
- 不支持复杂操作(如边删边改、插入等),仅用于“满足条件就移除”场景
多线程环境不能靠加锁 Iterator,要换容器
Iterator 的 fail-fast 不是线程安全方案。对 Collections.synchronizedList() 加锁遍历,仍需额外同步块保护整个迭代过程,极易遗漏且性能差。
立即学习“Java免费学习笔记(深入)”;
- 读多写少:选
CopyOnWriteArrayList,遍历时用快照,写操作复制数组,不抛 CME - 高并发读写 Map:用
ConcurrentHashMap,其keySet()和values()返回的 Iterator 是弱一致性的,不校验 modCount - 避免用普通 ArrayList + synchronized 块遍历——逻辑脆弱,易出错
复杂判断逻辑可暂存再统一删除
当删除条件涉及多个字段、外部状态或需要多次计算时,removeIf() 表达困难,又不想引入新集合类型,可用两阶段策略:
- 第一阶段:遍历原集合,只做判断,把待删元素加入临时集合(如
new ArrayList()) - 第二阶段:遍历结束后,调用
list.removeAll(toRemove);若原集合是 HashSet,用 HashSet 存待删项可提升效率 - 注意:临时集合应避免用 LinkedHashSet 等带顺序的类型,除非顺序对业务有意义


















