java集合迭代器采用fail-fast机制,直接调用集合remove()会因modcount校验失败抛concurrentmodificationexception;iterator.remove()同步更新expectedmodcount确保安全,但须在next()后且仅一次调用;removeif()是更安全简洁的替代方案。

因为 Java 集合的迭代器采用 fail-fast(快速失败)机制,调用集合自身的 remove() 会破坏迭代器内部状态,导致下一次 next() 或 hasNext() 立即抛出 ConcurrentModificationException;而 Iterator.remove() 是唯一被设计为同步更新状态的删除方式。
底层靠 modCount 校验一致性
每个可变集合(如 ArrayList、HashSet)都维护一个 modCount 字段,记录结构修改次数。迭代器创建时会把当前 modCount 复制为自己的 expectedModCount。每次调用 next() 前,都会检查两者是否相等。
- 调用
list.remove()→modCount自增,但expectedModCount不变 → 校验失败 → 抛异常 - 调用
it.remove()→ 迭代器自己执行删除,并同步更新expectedModCount→ 校验通过
Iterator.remove() 有严格使用前提
它不是“随便能用”的方法,而是受状态约束的:
- 必须在调用过
it.next()之后才能调用,否则抛IllegalStateException - 每次
next()后最多调用一次remove(),重复调用也会抛IllegalStateException - 不能在
hasNext()返回false后调用,也不能在遍历开始前调用
这不是线程安全问题,单线程也会触发
很多人误以为这是多线程导致的,其实完全不是。即使只在一个线程里,只要用错删除方式,就必然报错。比如这段代码:
表面看是单线程顺序执行,但 for-each 底层就是 Iterator,你在循环体里调 list.remove(),等于绕过迭代器直接改集合,立刻破坏一致性。
更简洁的替代方案:removeIf()
Java 8+ 提供了语义清晰、内部已封装迭代器逻辑的 removeIf(Predicate):
它本质就是帮你写了标准的 Iterator.remove() 流程,避免手写错误,也支持 lambda 表达式,推荐优先使用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











