唯一安全的方式是调用 iterator.remove(),因其能同步更新迭代器的 expectedmodcount,避免 concurrentmodificationexception;其他删除方式会破坏 modcount 一致性。

用 Iterator 迭代器在遍历时删除元素,唯一安全的方式是调用 iterator.remove(),且必须紧跟在 iterator.next() 之后执行。其他任何方式——比如在 for-each 里调用 list.remove(),或在普通 for 循环中直接删——都可能引发 ConcurrentModificationException 或漏删元素。
为什么只能用 iterator.remove()?
ArrayList、LinkedList、HashSet 等集合的迭代器是「快速失败」(fail-fast)的。它们内部维护一个 modCount 计数器,每次结构修改(如 add/remove)都会更新它。而迭代器自己也保存一份期望值 expectedModCount。只要外部方法(如 list.remove())修改了集合,modCount 就会与期望值不一致,下一次 next() 就抛异常。
iterator.remove() 是唯一被允许同步更新 expectedModCount 的入口,所以它不会破坏一致性。
标准写法:while + hasNext + next + remove
这是最通用、最不容易出错的写法,适用于 List、Set 和 Map.entrySet():
- 先获取迭代器:
Iterator<string> it = list.iterator();</string> - 用
while (it.hasNext())控制循环 - 每次循环内只调一次
it.next()获取当前元素 - 判断条件满足后,立刻调
it.remove()(不能隔行,不能重复调)
示例:
Iteratorwhile (it.hasNext()) {
String name = it.next();
if (name.startsWith("tmp")) {
it.remove(); // ✅ 正确位置
}
}
遍历 Map 时要先转 entrySet
Map 本身不支持直接迭代,需通过 map.entrySet().iterator() 获取键值对迭代器:
Iterator<map.entry>> it = map.entrySet().iterator();</map.entry>- 每次
it.next()返回的是Map.Entry对象 - 可读取
entry.getKey()和entry.getValue(),再决定是否删
注意:不能用 keySet().iterator() 删除 key 后再去 get value,那样可能 NPE;entrySet 是原子视图,更稳妥。
替代方案:removeIf() 和 Stream.filter()
如果只是简单条件过滤,Java 8+ 提供了更简洁的选项:
-
list.removeIf(s -> s == null || s.trim().isEmpty());—— 原地修改,底层仍用 Iterator,语义清晰 -
List<string> filtered = list.stream().filter(s -> !s.isEmpty()).collect(Collectors.toList());</string>—— 不修改原集合,生成新列表
两者都不触发 ConcurrentModificationException,但语义不同:removeIf() 是就地清理,stream().filter() 是不可变式处理。需要中途 break 或含 try-catch 逻辑时,还是得退回手动 Iterator。










