Java迭代器remove()必须先调next()再调用且仅一次,否则抛IllegalStateException;直接操作集合会触发ConcurrentModificationException;删除后next()自动返回下一元素,无需手动跳过。

在 Java 中,迭代器的 remove() 方法只能在调用过 next() 之后立即调用一次,否则会抛出 IllegalStateException;若在遍历过程中直接操作集合(如调用 list.remove()),则会触发 ConcurrentModificationException。正确使用的关键是:**严格遵循“先 next,再 remove”,且仅调用一次**。
必须配合 next() 使用
迭代器的 remove() 不是独立删除当前元素,而是删除上一次 next() 返回的那个元素。没有调用 next() 就调 remove(),或连续调两次 remove()(中间没再调 next()),都会报 IllegalStateException。
✅ 正确写法:
Iterator<string> it = list.iterator();
while (it.hasNext()) {
String s = it.next(); // 必须先调 next()
if ("target".equals(s)) {
it.remove(); // 紧接着、仅一次
}
}</string>
不能和集合自身 remove 混用
一旦用迭代器遍历,就不要再对原集合做增删改——哪怕是在不同线程也不行(除非用并发集合)。下面这种写法一定会崩溃:
// ❌ 危险!会导致 ConcurrentModificationException
for (String s : list) {
if ("bad".equals(s)) {
list.remove(s); // 错!该用 it.remove()
}
}
原因是增强 for 循环底层仍用迭代器,但你绕过它直接操作集合,破坏了迭代器的预期状态。
注意 remove 后的 next 行为
调用 remove() 后,迭代器内部游标不会后移,下一次 next() 会返回原本的下一个元素。也就是说,删除当前元素后,不会跳过后续元素。
例如列表为 ["a", "b", "c"],遍历时删掉 "b",接下来 next() 拿到的是 "c",不是跳过它。
⚠️ 所以不需要在 remove 后手动控制索引或跳过下轮循环。
多线程场景需换方案
单线程下用 Iterator.remove() 是安全的;但多线程遍历+修改,普通 ArrayList 或 LinkedList 的迭代器仍会抛异常。此时应:
- 用线程安全集合:如
CopyOnWriteArrayList(适合读多写少) - 加同步块包裹整个遍历逻辑(注意性能影响)
- 收集待删元素,遍历结束后统一调
removeAll()
例如:
List<string> toRemove = new ArrayList();
for (String s : list) {
if (shouldRemove(s)) toRemove.add(s);
}
list.removeAll(toRemove); // 安全,无并发风险</string>
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











