Java集合迭代“失效”实为Fail-Fast机制主动中断,通过ConcurrentModificationException提示结构性修改冲突;其核心是modCount与expectedModCount校验不一致所致。

Java 中的集合迭代“失效”不是真失效,而是 Fail-Fast 机制主动中断遍历,通过抛出 ConcurrentModificationException 提醒你:集合结构在迭代过程中被意外修改了。它不为线程安全兜底,只为尽早暴露逻辑错误。
核心是两个计数器对不上
每个支持 Fail-Fast 的集合(如 ArrayList、HashMap)内部维护一个 modCount,记录结构性修改次数(add、remove、clear 等会使其 +1);而迭代器创建时,会把当时的 modCount 值存为自己的 expectedModCount。后续每次调用 next() 或 remove() 前,都会执行校验:
- 如果
modCount == expectedModCount→ 正常继续 - 如果
modCount != expectedModCount→ 立即抛出ConcurrentModificationException
哪些操作会触发这个异常
关键看是否“绕过迭代器”改了集合结构:
- 增强 for 循环里写
list.remove(x) - 普通 for 循环中边
i < list.size()边调list.add()或list.remove() - 多线程下,一个线程用 iterator 遍历,另一个线程调
map.put()或list.clear() - 迭代器创建后,手动调
list.ensureCapacity()或map.retainAll()等影响内部结构的方法
注意:list.set()、map.get()、list.get() 不改变结构,不会触发。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
单线程也会报错,这不是多线程专属
很多人误以为 “Concurrent” 指多线程,其实它泛指“同时发生”的修改冲突。哪怕只有一条线程:
- 用
Iterator<String> it = list.iterator()开始遍历 - 中途写
list.remove("a")—— 这属于“非迭代器方式修改” - 下一次
it.next()就会检查失败,直接抛异常
这种设计目的很明确:防止一边读一边乱改导致数据错乱或无限循环,宁可停掉也不让程序带病运行。
怎么避免?关键在修改方式
不是不能改,而是得用迭代器自己提供的修改方法:
- 遍历时删除元素,用
iterator.remove()(安全,会同步更新expectedModCount) - 需要增删多个元素,先收集待操作项,遍历完再统一处理
- 多线程场景下,换用
CopyOnWriteArrayList或ConcurrentHashMap等 Fail-Safe 容器 - 临时需要修改,可用
new ArrayList(originalList)创建副本操作,原集合保持只读

















