Java中删除HashMap元素时出现ConcurrentModificationException问题
解决HashMap遍历删除元素时的ConcurrentModificationException问题
这个问题我之前也碰到过!原因很简单——HashMap的迭代器是fail-fast机制的,当你在遍历entrySet的同时直接调用map.remove()修改原集合的结构,迭代器会检测到这个变化,立刻抛出ConcurrentModificationException来提醒你操作不安全。下面给你几种靠谱的解决办法:
1. 使用迭代器的remove()方法(传统安全方案)
这是Java集合框架推荐的遍历删除方式,迭代器的remove()方法会同步更新迭代器和原集合的状态,不会触发异常:
import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.stream.IntStream; public class HelloWorld{ public static void main(String[] args) { Map<String, String> map = new HashMap<>(); IntStream.range(0, 20).forEach(i -> map.put(Integer.toString(i), i % 2 == 0 ? null : "ok")); Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, String> entry = iterator.next(); if (entry.getValue() == null) { iterator.remove(); // 用迭代器的remove方法,而非map的remove } } } }
2. 使用Java 8+的removeIf方法(最简洁方案)
Java 8为集合新增了removeIf方法,它内部会安全地使用迭代器完成删除操作,代码非常简洁:
import java.util.HashMap; import java.util.Map; import java.util.stream.IntStream; public class HelloWorld{ public static void main(String[] args) { Map<String, String> map = new HashMap<>(); IntStream.range(0, 20).forEach(i -> map.put(Integer.toString(i), i % 2 == 0 ? null : "ok")); // 直接通过entrySet的removeIf过滤掉value为null的条目 map.entrySet().removeIf(entry -> entry.getValue() == null); } }
3. 先收集待删除的Key,再批量删除(兼容旧版本的变通方案)
如果你的项目还在用Java 8之前的版本,可以先把所有需要删除的Key收集到一个列表里,再遍历列表删除——这样遍历的是独立的列表,不会触发原map的迭代器检测:
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.IntStream; public class HelloWorld{ public static void main(String[] args) { Map<String, String> map = new HashMap<>(); IntStream.range(0, 20).forEach(i -> map.put(Integer.toString(i), i % 2 == 0 ? null : "ok")); List<String> keysToRemove = new ArrayList<>(); // 先收集所有value为null的key for (Map.Entry<String, String> entry : map.entrySet()) { if (entry.getValue() == null) { keysToRemove.add(entry.getKey()); } } // 再批量删除 for (String key : keysToRemove) { map.remove(key); } } }
4. 使用Stream API生成新Map(不修改原Map的场景)
如果不需要修改原Map,而是要得到一个过滤后的新Map,用Stream API会很优雅:
import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.IntStream; public class HelloWorld{ public static void main(String[] args) { Map<String, String> map = new HashMap<>(); IntStream.range(0, 20).forEach(i -> map.put(Integer.toString(i), i % 2 == 0 ? null : "ok")); // 过滤出value不为null的条目,收集成新的HashMap Map<String, String> filteredMap = map.entrySet().stream() .filter(entry -> entry.getValue() != null) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (oldVal, newVal) -> oldVal, // 处理key冲突的逻辑(这里用旧值) HashMap::new // 指定收集为HashMap )); } }
内容的提问来源于stack exchange,提问作者Sk. Irfan
相关产品推荐
相关产品推荐

