必须用Iterator.remove()安全删除元素,因集合的“快速失败”机制会校验modCount,手动删除导致计数不匹配而抛ConcurrentModificationException;增强for循环本质是Iterator语法糖,内部删会报错;removeIf()、倒序遍历、先收集后删为替代方案。

在 Java 中遍历集合时安全删除元素,核心就一条:必须用 Iterator.remove(),且只能在调用过 next() 之后立即调用。
为什么不能直接删
ArrayList、HashSet 等集合内置“快速失败”机制:迭代器创建时会记录一个修改计数器(modCount),每次调用 list.remove() 或 set.add() 都会让它加一。而迭代器在每次 next() 前都会校验这个值是否匹配。你手动删,计数器就对不上,立刻抛 ConcurrentModificationException——这不是多线程问题,单线程也会崩。
增强 for 循环(for (x : list))本质就是 Iterator 的语法糖,但你不暴露迭代器引用,所以里面写 list.remove(x) 必然报错。
Iterator.remove() 的正确用法
这个方法是唯一被设计为与遍历协同的删除方式。它内部会同步更新计数器,避免校验失败。
- 必须先调
it.next(),拿到当前元素,再紧跟着调it.remove() - 每个
next()最多配一次remove();重复调或没调next()就调,会抛IllegalStateException - 删的是上一次
next()返回的那个元素,不是“当前看着想删的”那个逻辑位置
示例(删掉所有空字符串):
Iterator
while (it.hasNext()) {
String s = it.next();
if (s == null || s.trim().isEmpty()) {
it.remove(); // ✅ 安全
}
}
其他可行但有局限的方式
removeIf()(Java 8+):一行搞定,语义清晰,底层仍是 Iterator.remove(),推荐用于简单条件。
list.removeIf(s -> s == null || s.trim().isEmpty());
倒序 for 循环:只适用于 ArrayList 这类支持随机访问的 List。从末尾开始删,前面索引不受影响。
for (int i = list.size() - 1; i >= 0; i--) {
if (list.get(i) == null) {
list.remove(i); // ✅ 安全,但不适用于 LinkedList
}
}
先收集后批量删:适合要记录被删项、或多条件组合判断的场景,但会额外占用内存,且 removeAll() 对 ArrayList 是 O(n×m) 复杂度。
特别注意
Map 不支持直接迭代删除,得转成 entrySet() 再用 Iterator 或 removeIf();Collections.unmodifiableList() 返回的集合调 remove() 会直接抛 UnsupportedOperationException;并发环境下,哪怕用了 Iterator.remove(),其他线程同时修改集合仍可能触发异常,此时应换用 CopyOnWriteArrayList 或加锁。


















