Java中遍历时删除元素必须用Iterator.remove(),因其同步更新expectedModCount;若用集合自身remove()或并发修改会触发ConcurrentModificationException。
在 java 中,直接用 while 循环配合 iterator.hasnext() 并不能规避并发修改异常(concurrentmodificationexception),关键在于:必须使用迭代器自身的 remove() 方法删除元素,且不能在遍历过程中通过集合本身(如 list.remove())或其它线程修改集合结构。
为什么会出现 ConcurrentModificationException
Java 集合(如 ArrayList、HashMap)的迭代器是“快速失败”(fail-fast)的。当迭代器创建后,若集合被非迭代器方式结构性修改(增、删元素),其内部的 modCount 与迭代器记录的 expectedModCount 不一致,下次调用 hasNext() 或 next() 就会抛出异常。
正确写法:只用 Iterator.remove() 删除
这是最常用且安全的方式——遍历时删除当前元素,必须调用 iterator.remove(),而不是集合的 remove():
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c", "b"));
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if ("b".equals(s)) {
it.remove(); // ✅ 安全:迭代器自己负责同步状态
}
}
// 结果:["a", "c"]
-
it.remove()会同步更新expectedModCount,避免下一次hasNext()检查失败 - 每个
it.next()后最多调用一次it.remove();重复调用会抛IllegalStateException - 不能在
hasNext()前调用remove()(尚未定位元素)
需要修改多个元素?用 ListIterator 或倒序 for 循环
如果需在遍历时插入、双向遍历或批量删除,ListIterator 更灵活;若只需删除,倒序索引循环也可避开迭代器限制:
// 方式1:ListIterator(支持 add/set/remove)
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {
if ("c".equals(lit.next())) {
lit.set("replaced"); // ✅ 替换当前元素
lit.add("new"); // ✅ 在当前后插入
}
}
<p>// 方式2:倒序 for 循环(避免索引错位)
for (int i = list.size() - 1; i >= 0; i--) {
if ("a".equals(list.get(i))) {
list.remove(i); // ✅ 安全:不依赖迭代器
}
}</p>多线程场景?必须加同步或换并发集合
单线程下用 Iterator.remove() 足够;但若有多个线程同时读写同一集合,仅靠迭代器无法解决:
立即学习“Java免费学习笔记(深入)”;
- 加显式同步:用
synchronized(list)包裹整个遍历+修改块 - 换线程安全集合:如
CopyOnWriteArrayList(适合读多写少)、ConcurrentLinkedQueue - 注意:
Vector和Stack虽方法同步,但迭代仍可能抛异常——它们的迭代器仍是 fail-fast 的


















