遍历map时直接调用map.remove()会触发concurrentmodificationexception,因hashmap的快速失败机制检测到非法结构修改;安全方式有三:①iterator的remove()(最通用,需先next()再remove);②java 8+的entryset().removeif()(简洁高效,适合单条件);③先收集key再批量removeall()(适合多条件或复杂逻辑);禁用增强for、普通for或stream中调map.remove()。

在Map遍历中直接调用map.remove()会触发ConcurrentModificationException,这不是因为多线程,而是HashMap的“快速失败”机制检测到结构被非法修改。安全删除的关键是使用与遍历耦合的、受控的移除方式。
用Iterator的remove()方法(最通用可靠)
这是JDK所有版本都支持、且语义最明确的安全方式。Iterator的remove()是唯一被设计用于遍历中删当前元素的方法,它会同步更新内部状态,避免modCount校验失败。
- 必须先调
next()获取元素,再调remove();否则抛IllegalStateException - 每次只能删一个,不能连续调两次
remove() - 推荐遍历
entrySet(),兼顾key和value判断
示例:
Iteratorwhile (it.hasNext()) {
Map.Entry
if (entry.getValue() it.remove(); // ✅ 安全
}
}
用removeIf()(Java 8+,简洁高效)
Map本身不提供removeIf,但它的keySet()、values()和entrySet()都继承自Collection,支持该方法。底层仍基于Iterator,但封装了逻辑,一行代码解决常见过滤删除。
- 语义清晰,适合单条件批量删除(如按值、按key前缀、按null判断)
- 不可用于需在删除前执行复杂逻辑或保留被删元素信息的场景
示例:
map.entrySet().removeIf(entry -> entry.getKey().startsWith("tmp") || entry.getValue() == null);先收集key,再批量删除(适合多条件或预处理逻辑)
当删除条件分散、需多次计算、或涉及跨集合比对时,可先缓存待删key,遍历结束后统一移除。虽稍占内存,但逻辑解耦、不易出错。
- 用
HashSet暂存key(避免重复key导致误删) - 最后调
map.keySet().removeAll(keysToRemove),线程安全且无异常 - 注意:不要在遍历中用
map.remove(key)逐个删,仍会触发异常
示例:
Setfor (Map.Entry
if (e.getValue() toRemove.add(e.getKey());
}
}
map.keySet().removeAll(toRemove); // ✅ 批量安全
绝对要避免的操作
以下写法无论单线程还是多线程,都会抛ConcurrentModificationException:
- 增强for循环中调
map.remove(key) - 普通for循环遍历
keySet()或entrySet()时调map.remove() - 用
stream().filter().forEach(...map.remove...)——Stream遍历也是基于Iterator,中途改结构即报错











