遍历集合时修改元素触发ConcurrentModificationException,本质是迭代器通过modCount与expectedModCount不一致检测到结构修改,属fail-fast机制;解决方式包括:①用Iterator.remove()安全删除;②收集待操作元素后统一处理;③多线程下选用并发集合;④转Stream.collect生成新集合。

遍历集合时修改元素触发 ConcurrentModificationException,本质是迭代器检测到集合结构被意外修改(比如 add/remove),它通过 modCount 与 expectedModCount 不一致来抛出异常。这不是线程安全问题(单线程也会发生),而是“快速失败”(fail-fast)机制的正常表现。解决方向明确:避免在遍历过程中直接调用集合的结构性修改方法。
用 Iterator 的 remove() 安全删除
这是最常用、最推荐的方式。Iterator 提供了 remove() 方法,它会在删除的同时同步更新内部状态,不会破坏一致性。
- 只能在调用
next()之后立即调用一次remove() - 不能用于添加元素,仅支持删除当前迭代位置的元素
- 示例:
收集待操作元素,遍历结束后统一处理
适合需要增删多个元素,或逻辑较复杂的情况。先用另一个集合暂存要删除/修改的目标,再批量操作原集合。
- 删除:用
removeAll()或循环调用remove()(此时已退出迭代) - 添加:直接调用
addAll(),不影响正在遍历的快照 - 注意:如果用普通 for 循环 + 索引删除,需倒序遍历,否则下标会错位
使用并发集合(仅适用于多线程场景)
如果问题确实源于多线程并发修改,才考虑换成线程安全的集合类,但要注意它们的行为差异:
立即学习“Java免费学习笔记(深入)”;
-
CopyOnWriteArrayList:写操作复制整个数组,读操作无锁,适合读多写少;迭代器基于快照,遍历时修改不影响当前迭代 -
ConcurrentHashMap:不支持entrySet().iterator()中修改,但可用computeIfPresent、remove(key, value)等原子方法 - 注意:并发集合不能解决单线程中的 fail-fast 报错,它只是绕开了该机制
转为 Stream + collect 收集新集合
函数式风格,不修改原集合,而是生成新结果。适合过滤、转换类操作,语义清晰且线程安全(无副作用)。
- 用
filter()、map()处理,最后collect(Collectors.toList())得到新列表 - 原集合保持不变,彻底规避结构修改冲突
- 示例:


















