在HashSet遍历中安全删除元素有三种方式:①使用Iterator的remove()方法;②先收集待删元素再调用removeAll();③使用Java 8+的removeIf()。禁止在增强for循环中直接调用set.remove(),否则抛ConcurrentModificationException。

在 Java 中,直接在 HashSet 遍历过程中调用 remove() 方法会抛出 ConcurrentModificationException。这是因为增强 for 循环(或迭代器隐式使用)依赖于集合的结构性修改计数(modCount),而手动调用 set.remove() 会改变结构但不通知当前迭代器。
使用 Iterator 的 remove() 方法
这是最常用、最安全的方式:获取显式 Iterator,并在遍历时调用其 remove() 方法(该方法专为边遍历边删除设计)。
- 必须在
next()调用之后、且仅调用一次remove(),否则抛出IllegalStateException - 不能与集合自身的
remove()混用
HashSet<String> set = new HashSet<>(Arrays.asList("a", "b", "c", "d"));
Iterator<String> it = set.iterator();
while (it.hasNext()) {
String s = it.next();
if ("b".equals(s) || "c".equals(s)) {
it.remove(); // ✅ 安全删除
}
}
// set 现在为 ["a", "d"]
收集待删元素,遍历结束后批量删除
适合需要复杂判断逻辑,或删除条件分散、不易在单次遍历中统一处理的场景。
- 先遍历集合,把要删的元素存入临时容器(如
ArrayList或HashSet) - 再调用
set.removeAll(toRemove)批量移除(注意:removeAll时间复杂度取决于实现,对HashSet是 O(n))
HashSet<String> set = new HashSet<>(Arrays.asList("a", "b", "c", "d"));
Set<String> toRemove = new HashSet<>();
for (String s : set) {
if (s.length() == 1 && s.charAt(0) >= 'b') {
toRemove.add(s);
}
}
set.removeAll(toRemove); // ✅ 安全,无并发修改问题
使用 removeIf()(Java 8+)
简洁、函数式风格,内部已封装安全的迭代逻辑,推荐用于简单条件删除。
立即学习“Java免费学习笔记(深入)”;
- 参数是
Predicate<e></e>,返回true表示要删除 - 底层仍基于
Iterator.remove(),线程安全仅限单线程环境(本身不是线程安全集合)
HashSet<String> set = new HashSet<>(Arrays.asList("a", "b", "c", "d"));
set.removeIf(s -> "b".equals(s) || "c".equals(s)); // ✅ 一行搞定
避免的写法
以下操作都会触发 ConcurrentModificationException:
- 增强 for 循环中调用
set.remove() - 用普通 for 循环按索引操作(
HashSet无索引,get(i)不存在) - 多线程环境下未加同步就并发遍历 + 修改(即使用了
Iterator.remove())
// ❌ 危险!运行时异常
for (String s : set) {
if ("b".equals(s)) {
set.remove(s); // 抛 ConcurrentModificationException
}
}


















