Java中遍历集合时安全删除元素必须使用Iterator.remove(),不可直接调用集合remove(),否则抛ConcurrentModificationException;Java 8+推荐用stream().filter().collect()或removeIf()替代。

在 Java 中,遍历集合时用迭代器做条件过滤,核心是“边遍历、边判断、边移除”——但必须用 Iterator.remove(),不能直接调用集合的 remove(),否则会抛 ConcurrentModificationException。
用迭代器安全地过滤并删除匹配元素
这是最经典、最稳妥的方式,适用于所有实现了 Iterable 的集合(如 ArrayList、LinkedList、HashSet 等),尤其适合需要在遍历时动态删减数据的场景。
- 先调用
iterator()获取迭代器 - 用
hasNext()判断是否还有元素 - 每次调用
next()取出当前元素后,立即根据条件决定是否调用remove() -
注意:
remove()必须紧跟在一次next()之后,且每调用一次next()最多只能调用一次remove()
示例:删除列表中所有偶数
List<Integer> nums = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6));Iterator<Integer> it = nums.iterator();
while (it.hasNext()) {
Integer n = it.next();
if (n % 2 == 0) {
it.remove(); // 安全删除
}
}
// 结果:[1, 3, 5]
Java 8+ 更简洁的替代方案
如果目标只是“筛选出符合条件的元素”,而非原地修改原集合,推荐使用 Stream API,它语义更清晰、代码更简短,且天然支持链式操作。
立即学习“Java免费学习笔记(深入)”;
-
stream().filter(...).collect(...):生成新集合,不改变原集合 -
removeIf(...):直接在原集合上删除匹配项,底层已封装迭代逻辑,线程安全需自行保障
示例:保留所有奇数(生成新列表)
List<Integer> filtered = nums.stream().filter(n -> n % 2 != 0)
.collect(Collectors.toList());
等价于原地删除偶数:
nums.removeIf(n -> n % 2 == 0);需要自定义过滤逻辑?考虑可复用的迭代器
当过滤规则复杂、频繁复用(比如按权限、状态、时间范围组合过滤),可以封装一个带谓词(Predicate)的装饰迭代器,例如 FilteringIterator。
- 继承或包装原始迭代器,重写
hasNext()和next(),跳过不满足条件的元素 - 避免一次性加载全部数据,适合大数据量或流式处理场景
- 注意:这种迭代器通常只读,不支持
remove(),若需删除仍得配合原集合操作
Map 集合的迭代器过滤要特别注意
Map 本身不直接实现 Iterable,但它的视图(keySet()、values()、entrySet())都支持迭代器。过滤时建议操作 entrySet(),避免重复查值。
- 错误做法:遍历
keySet(),再用get()查值 → 多次哈希查找,性能差 - 推荐做法:遍历
entrySet(),直接访问entry.getKey()和entry.getValue() - 删除时调用
entryIterator.remove(),安全高效
示例:删除 value 小于 60 的成绩记录
Iterator<Map.Entry<String, Integer>> it = studentScores.entrySet().iterator();while (it.hasNext()) {
Map.Entry<String, Integer> entry = it.next();
if (entry.getValue() < 60) {
it.remove();
}
}


















