Iterator.remove() 同步更新 expectedModCount 以避免 ConcurrentModificationException,而集合自身 remove() 仅修改 modCount 导致校验失败;fail-fast 机制通过对比 modCount 与 expectedModCount 实现遍历一致性保护。

因为 Iterator.remove() 会同步更新迭代器内部的 expectedModCount,使其始终与集合的 modCount 保持一致;而集合自身的 remove() 只修改 modCount,却不通知迭代器,导致下一次调用 next() 时校验失败,抛出 ConcurrentModificationException。
fail-fast 机制靠“对账”工作
Java 集合(如 ArrayList、HashSet)内部维护一个 modCount 字段,记录结构修改次数(增、删、清空都会 +1)。迭代器创建时,会把当时的 modCount 值存为自己的 expectedModCount。之后每次调用 next() 前,都会检查两者是否相等——不等就立即报错。
Iterator.remove() 的三步闭环动作
- 必须在
next()之后调用,此时lastRet已记录被遍历元素的索引 - 内部真正执行
ArrayList.this.remove(lastRet),即时从底层数组中删除元素 - 紧接着执行
expectedModCount = modCount,完成计数器同步 - 重置
lastRet = -1,防止重复调用
集合自身 remove() 为什么危险
它只改了 modCount,但没动迭代器的 expectedModCount。下一次 next() 就发现“账对不上”,不管是不是单线程,都立刻触发异常。这不是线程安全问题,而是设计上对遍历一致性的强制保护。
常见错误写法对比
❌ 增强 for 循环中调 list.remove():
for (String s : list) { if (s.length() > 5) list.remove(s); }
→ 底层仍是 Iterator,但你拿不到引用,无法调 it.remove(),必然报错。
✅ 正确写法:
Iterator
while (it.hasNext()) {
String s = it.next();
if (s.length() > 5) it.remove();
}


















