Java集合迭代失效本质是Iterator对遍历契约的严格履行:创建迭代器后集合结构被快照锁定,外部结构性修改导致modCount与expectedModCount不一致,next()即抛ConcurrentModificationException;Iterator.remove()是唯一受控例外,因它同步更新expectedModCount;Fail-Fast用于单线程逻辑校验,非并发控制;需遍历中修改时应换用CopyOnWriteArrayList、ConcurrentHashMap或Stream等适配新契约的方案。

Java 中集合迭代失效机制,本质是 Iterator 设计模式对“遍历契约”的严格履行——它不保证线程安全,但坚决捍卫遍历过程的逻辑一致性。
迭代器失效不是 Bug,而是契约违约的即时反馈
Iterator 接口隐含一个关键契约:一旦迭代器被创建,集合的结构性状态就被“快照锁定”。后续所有遍历操作(next()、hasNext())都默认该状态未被外部篡改。当集合通过 add()、remove()、clear() 等方式发生结构性修改时,modCount 自增,而迭代器持有的 expectedModCount 未同步更新,下一次调用 next() 就会触发 ConcurrentModificationException。这不是系统崩溃,而是设计者主动抛出的“违约警告”。
Iterator.remove() 是唯一被契约允许的例外
这个方法之所以安全,是因为它在删除元素后立即执行 expectedModCount = modCount,主动维持了状态一致性。这体现了契约的灵活性——只禁止“不可控修改”,不禁止“受控修改”。
- ✅ 允许:it.next(); it.remove();(一次 next 后紧跟一次 remove)
- ❌ 禁止:list.remove(obj)、list.add(obj)、it.remove(); it.remove();(重复调用或未先调用 next)
Fail-Fast 不是并发控制,而是单线程逻辑校验
很多人误以为这个机制专为多线程设计,其实不然。即使在单线程中,以下代码也会失败:
立即学习“Java免费学习笔记(深入)”;
List<String> list = new ArrayList<>(Arrays.asList("a", "b"));
Iterator<String> it = list.iterator();
list.add("c"); // 违约:在迭代器创建后直接改集合
it.next(); // 立即抛 ConcurrentModificationException
它的真正价值在于:及早暴露“边遍历边随意改集合”这类常见逻辑错误,避免产生难以复现的空指针、越界或漏遍历等隐蔽问题。
契约失效时的替代方案,不是绕过,而是换约
当业务确实需要遍历中修改,不应试图屏蔽异常,而应选择符合新需求的契约:
- 读多写少场景 → 用 CopyOnWriteArrayList(迭代器基于快照,天然支持并发读+少量写)
- 键值映射场景 → 用 ConcurrentHashMap(其迭代器弱一致,不抛异常,也不阻塞)
- 过滤重建场景 → 改用 Stream.filter().collect() 或预收集待删元素再批量移除
这些不是“修复 Iterator”,而是选用另一套更匹配的遍历契约。


















