Java中唯一安全的遍历中删除方式是Iterator.remove(),必须先调用next()再调remove(),且每次next()后最多调一次;直接调集合remove()会因modCount与expectedModCount不一致触发ConcurrentModificationException。

Java Iterator 本身不支持集合的动态更新,但提供了唯一安全的遍历中删除方式——通过迭代器自身的 remove() 方法。关键不是“更新集合”,而是“在遍历时安全地修改结构”。直接调用集合的 add()、remove() 或 clear() 等方法,会立即触发 ConcurrentModificationException。
为什么不能直接改集合?
Iterator 内部维护一个 modCount(修改计数器),每次集合结构变化(如增删元素)都会更新它。而迭代器在创建时会记录初始值(expectedModCount)。一旦两者不一致,next() 或 hasNext() 就会抛出异常——这是快速失败(fail-fast)机制,用来防止遍历结果错乱或漏项。
安全删除:只能用 iterator.remove()
这是迭代器唯一允许的结构性修改操作,且有严格前提:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 必须先调用过
next(),否则抛IllegalStateException - 每个
next()后最多调一次remove(),重复调用也抛IllegalStateException -
remove()删除的是上一次next()返回的那个元素
想添加或替换元素?换 ListIterator
如果需要在遍历时插入、反向遍历或设置(替换)当前元素,应使用 ListIterator(仅适用于 List 实现类):
立即学习“Java免费学习笔记(深入)”;
-
add(E e):在当前位置前插入,不影响后续遍历 -
set(E e):替换上一次next()或previous()返回的元素 -
previous()和hasPrevious():支持双向移动
其他“动态更新”场景的替代方案
若需求超出迭代器能力(如边遍历边批量添加、并发修改),推荐以下更稳妥的做法:
- 收集待操作元素(如要删的姓名、要加的对象),遍历结束后统一处理
- 使用
Collection.removeIf(Predicate)(JDK 8+),内部基于迭代器,线程安全且简洁 - 对高并发场景,改用
CopyOnWriteArrayList或ConcurrentHashMap等线程安全集合,它们的迭代器不抛ConcurrentModificationException

















