Java中如何从HashMap移除k个值最大的元素?
问题原因与解决方案
你遇到的ConcurrentModificationException是因为HashMap的迭代器是快速失败的:当你用增强for循环遍历entrySet时,底层依赖HashMap内置的迭代器工作,这时候直接调用hMap.remove(key)修改Map结构,迭代器会立刻检测到这个非法修改并抛出异常——它不允许遍历和直接修改Map结构同时进行(除非用迭代器自身的修改方法)。
另外你代码里还有个笔误:定义的Map变量是myMap,删除时却用了hMap,需要统一。
下面给出几种可行的解决方法:
方法1:使用迭代器的remove()方法
把增强for循环换成显式的Iterator遍历,找到目标元素时调用迭代器的remove()方法,这是迭代器允许的合法修改方式,不会触发异常:
int k = 3; HashMap<Integer, Integer> myMap = new HashMap<>(Map.of(1,3,2,2,3,6,4,8,5,2,6,1)); for (int i = 0; i < k; i++) { Integer maxVal = Collections.max(myMap.values()); Iterator<Map.Entry<Integer, Integer>> iterator = myMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<Integer, Integer> entry = iterator.next(); if (entry.getValue().equals(maxVal)) { iterator.remove(); // 用迭代器的remove方法,避免并发修改异常 break; // 找到一个最大值就退出,确保每次循环只删一个元素 } } } System.out.println(myMap); // 输出 {2=2, 5=2, 6=1}
方法2:先收集待删除的键,再批量删除
先通过Stream筛选出前k个最大值对应的键,再批量删除,这种方式更高效,尤其适合元素较多的场景:
int k = 3; HashMap<Integer, Integer> myMap = new HashMap<>(Map.of(1,3,2,2,3,6,4,8,5,2,6,1)); // 按值从大到小排序,取前k个键 List<Integer> keysToRemove = myMap.entrySet() .stream() .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())) .limit(k) .map(Map.Entry::getKey) .toList(); keysToRemove.forEach(myMap::remove); System.out.println(myMap); // 输出 {2=2, 5=2, 6=1}
方法3:避开迭代时修改Map的逻辑
如果不想用迭代器或Stream,可以先找到当前最大值对应的键,再单独删除(不在遍历entrySet的过程中修改Map):
int k = 3; HashMap<Integer, Integer> myMap = new HashMap<>(Map.of(1,3,2,2,3,6,4,8,5,2,6,1)); for (int i = 0; i < k; i++) { Integer maxVal = Collections.max(myMap.values()); Integer keyToRemove = null; // 先找到要删除的键 for (Map.Entry<Integer, Integer> entry : myMap.entrySet()) { if (entry.getValue().equals(maxVal)) { keyToRemove = entry.getKey(); break; } } // 单独删除,不在遍历迭代器时修改 if (keyToRemove != null) { myMap.remove(keyToRemove); } } System.out.println(myMap); // 输出 {2=2, 5=2, 6=1}
注意细节
- 比较Integer值时尽量用
equals()而非==,因为Integer有缓存池,超过范围的数值用==会比较对象地址,导致判断错误。
内容的提问来源于stack exchange,提问作者blindflip
相关产品推荐
相关产品推荐

