因为遍历集合时直接删除元素会引发 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() 后
}
}
</string>
错误写法示例:
- 连续调两次
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 <p>注意:<code>remove()</code> 不影响后续 <code>hasNext()</code> 判断,它只是把当前节点从链表/数组中摘除,迭代器内部指针已自动前移。</p> <h3>并发场景下 Iterator.remove() 依然不安全</h3> <p>即使用了 <code>iterator.remove()</code>,如果其他线程同时修改同一集合(比如另一个线程调用 <code>list.add()</code>),仍可能抛 <code>ConcurrentModificationException</code>。这不是 bug,是 fail-fast 的设计意图——它只保证单线程下的结构一致性检查,不提供并发安全。</p> <p>真正需要多线程安全遍历+删除时,应考虑:</p> <ul> <li>用 <code>CopyOnWriteArrayList</code>(适合读多写少,但 <code>remove()</code> 性能差)</li> <li>加显式锁(如 <code>synchronized(list)</code> 包裹整个迭代块)</li> <li>改用 <code>ConcurrentHashMap</code> 的 <code>keySet().iterator()</code>(其 <code>remove()</code> 是线程安全的,但语义是弱一致:可能看不到其他线程刚做的修改)</li> </ul> <p>最常被忽略的一点:<code>Iterator.remove()</code> 的安全性完全依赖于集合实现是否遵守规范。自定义集合若未正确更新 <code>modCount</code> 或未在 <code>remove()</code> 中同步状态,照样出错。</p></string>










