因为遍历集合时直接删除元素会引发 ConcurrentModificationException 异常或导致漏删;for-each 依赖迭代器,删除后 modCount 与 expectedModCount 不一致;普通 for 循环正向遍历时,删除元素会导致后续元素索引前移而被跳过。

为什么不能直接用 for-each 或普通 for 循环删元素
直接在 for (String s : list) 或 for (int i = 0; i 中调用 <code>list.remove(...),会触发 ConcurrentModificationException(除非是 CopyOnWriteArrayList)。这是因为大多数集合(如 ArrayList、HashMap 的 keySet)的迭代器是「快速失败」(fail-fast)的——内部有 modCount 计数器,一旦检测到结构被外部修改(非通过 Iterator.remove()),就立即抛异常。
必须用 Iterator.remove(),且只能紧跟在 next() 之后调用
Iterator 提供了安全删除的唯一合法方式:iterator.remove()。但它有严格前提:必须在调用过 next() 之后、且尚未再次调用 next() 前执行,否则抛 IllegalStateException。
常见写法:
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next(); // 必须先调用 next()
if (s.startsWith("a")) {
it.remove(); // ✅ 正确:紧跟 next() 后
}
}
错误写法示例:
- 连续调两次
it.remove()(中间没next())→IllegalStateException - 在
hasNext()返回true后,不调next()就remove()→IllegalStateException - 用
list.remove(...)替代it.remove()→ConcurrentModificationException
remove() 是唯一安全的删除方式,但不支持批量或条件跳过
Iterator.remove() 每次只删当前元素,无法跳过下一个、也不能一次删多个。如果逻辑复杂(比如“删掉前两个匹配项后停止”),需手动维护计数或状态变量。
例如删前两个以 "b" 开头的字符串:
Iterator<String> it = list.iterator();
int removed = 0;
while (it.hasNext() && removed < 2) {
String s = it.next();
if (s.startsWith("b")) {
it.remove();
removed++;
}
}
注意:remove() 不影响后续 hasNext() 判断,它只是把当前节点从链表/数组中摘除,迭代器内部指针已自动前移。
并发场景下 Iterator.remove() 依然不安全
即使用了 iterator.remove(),如果其他线程同时修改同一集合(比如另一个线程调用 list.add()),仍可能抛 ConcurrentModificationException。这不是 bug,是 fail-fast 的设计意图——它只保证单线程下的结构一致性检查,不提供并发安全。
真正需要多线程安全遍历+删除时,应考虑:
- 用
CopyOnWriteArrayList(适合读多写少,但remove()性能差) - 加显式锁(如
synchronized(list)包裹整个迭代块) - 改用
ConcurrentHashMap的keySet().iterator()(其remove()是线程安全的,但语义是弱一致:可能看不到其他线程刚做的修改)
最常被忽略的一点:Iterator.remove() 的安全性完全依赖于集合实现是否遵守规范。自定义集合若未正确更新 modCount 或未在 remove() 中同步状态,照样出错。

















