Java HashMap 如何正确遍历并删除元素
(一)HashMap的遍历
HashMap的遍历主要有两种方式:
第一种采用的是foreach模式,适用于不需要修改HashMap内元素的遍历,只需要获取元素的键/值的情况。
HashMap<K, V> myHashMap;
for (Map.entry<K, V> item : myHashMap.entrySet()){
K key = item.getKey();
V val = item.getValue();
//todo with key and val
//WARNING: DO NOT CHANGE key AND val IF YOU WANT TO REMOVE ITEMS LATER
}
第二种采用迭代器遍历,不仅适用于HashMap,对其它类型的容器同样适用。
采用这种方法的遍历,可以用下文提及的方式安全地对HashMap内的元素进行修改,并不会对后续的删除操作造成影响。
for (Iterator<Map.entry<K, V>> it = myHashMap.entrySet().iterator; it.hasNext();){
Map.Entry<K, V> item = it.next();
K key = item.getKey();
V val = item.getValue();
//todo with key and val
//you may remove this item using "it.remove();"
}
(二)HashMap之删除元素
如果采用第一种的遍历方法删除HashMap中的元素,Java很有可能会在运行时抛出异常。
HashMap<String, Integer> myHashMap = new HashMap<>();
myHashMap.put("1", 1);
myHashMap.put("2", 2);
for (Map.Entry<String, Integer> item : myHashMap.entrySet()){
myHashMap.remove(item.getKey());
}
for (Map.Entry<String, Integer> item : myHashMap.entrySet()){
System.out.println(item.getKey());
}
运行上面的代码,Java抛出了 java.util.ConcurrentModificationException 的异常。并附有如下信息。
at java.util.HashMap$HashIterator.nextNode(Unknown Source)
at java.util.HashMap$EntryIterator.next(Unknown Source)
at java.util.HashMap$EntryIterator.next(Unknown Source)
可以推测,由于我们在遍历HashMap的元素过程中删除了当前所在元素,下一个待访问的元素的指针也由此丢失了。
所以,我们改用第二种遍历方式。
代码如下:
for (Iterator<Map.Entry<String, Integer>> it = myHashMap.entrySet().iterator(); it.hasNext();){
Map.Entry<String, Integer> item = it.next();
//... todo with item
it.remove();
}
for (Map.Entry<String, Integer> item : myHashMap.entrySet()){
System.out.println(item.getKey());
}
运行结果没有显示,表明HashMap中的元素被正确删除了。
(三)在HashMap的遍历中删除元素的特殊情况
上述方法可能足以应付多数的情况,但是如果你的HashMap中的键值同样是一个HashMap,假设你需要处理的是 HashMap<HashMap<String, Integer>, Double> myHashMap 时,很不碰巧,你可能需要修改myHashMap中的一个项的键值HashMap中的某些元素,之后再将其删除。
这时,单单依靠迭代器的 remove() 方法是不足以将该元素删除的。
例子如下:
HashMap<HashMap<String, Integer>, Integer> myHashMap = new HashMap<>();
HashMap<String, Integer> temp = new HashMap<>();
temp.put("1", 1);
temp.put("2", 2);
myHashMap.put(temp, 3);
for (Iterator<Map.Entry<HashMap<String, Integer>, Integer>>
it = myHashMap.entrySet().iterator(); it.hasNext();){
Map.Entry<HashMap<String, Integer>, Integer> item = it.next();
item.getKey().remove("1");
System.out.println(myHashMap.size());
it.remove();
System.out.println(myHashMap.size());
}
结果如下:
1
1
虽然 it.remove(); 被执行,但是并没有真正删除元素。
原因在于期望删除的元素的键值(即 HashMap<String, Integer> temp )被修改过了。
解决方案:
既然在这种情况下,HashMap中被修改过的元素不能被删除,那么不妨直接把待修改的元素直接删除,再将原本所需要的“修改过”的元素加入HashMap。
想法很好,代码如下:
for (Iterator<Map.Entry<HashMap<String, Integer>, Integer>>
it = myHashMap.entrySet().iterator(); it.hasNext();){
Map.Entry<HashMap<String, Integer>, Integer> item = it.next();
//item.getKey().remove("1");
HashMap<String, Integer> to_put = new HashMap<>(item.getKey());
to_put.remove("1");
myHashMap.put(to_put, item.getValue());
System.out.println(myHashMap.size());
it.remove();
System.out.println(myHashMap.size());
}
但是依然是RE:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.remove(Unknown Source)
原因在于,迭代器遍历时,每一次调用 next() 函数,至多只能对容器修改一次。上面的代码则进行了两次修改:一次添加,一次删除。
既然 java.util.ConcurrentModificationException 异常被抛出了,那么去想办法拿掉这个异常即可。
最后的最后,我决定弃HashMap转投ConcurrentHashMap。将myHashMap定义为ConcurrentHashMap之后,其它代码不动。
运行结果如下:
2
1
最终,通过ConcurrentHashMap和一些小技巧的使用,变形实现了对被修改过键值的元素的删除。
Java HashMap 如何正确遍历并删除元素的更多相关文章
- Java中ArrayList循环遍历并删除元素的陷阱
ava中的ArrayList循环遍历并且删除元素时经常不小心掉坑里,昨天又碰到了,感觉有必要单独写篇文章记一下. 先写个测试代码: import java.util.ArrayList; public ...
- 【Java】List遍历时删除元素的正确方式
当要删除ArrayList里面的某个元素,一不注意就容易出bug.今天就给大家说一下在ArrayList循环遍历并删除元素的问题.首先请看下面的例子: import java.util.ArrayLi ...
- JAVA List 一边遍历一边删除元素
JAVA List 一边遍历一边删除元素,报java.util.ConcurrentModificationException异常 2015年02月10日 14:42:49 zhanzkw 阅读数:3 ...
- 【原理探究】女朋友问我ArrayList遍历时删除元素的正确姿势是什么?
简介 我们在项目开发过程中,经常会有需求需要删除ArrayList中的某个元素,而使用不正确的删除方式,就有可能抛出异常.或者在面试中,会遇到面试官询问遍历时如何正常删除元素.所以在本篇文章中,我们会 ...
- java list集合遍历时删除元素
转: java list集合遍历时删除元素 大家可能都遇到过,在vector或arraylist的迭代遍历过程中同时进行修改,会抛出异常java.util.ConcurrentModification ...
- 【转】ArrayList循环遍历并删除元素的常见陷阱
转自:https://my.oschina.net/u/2249714/blog/612753?p=1 在工作和学习中,经常碰到删除ArrayList里面的某个元素,看似一个很简单的问题,却很容易出b ...
- ArrayList循环遍历并删除元素的常见陷阱
在工作和学习中,经常碰到删除ArrayList里面的某个元素,看似一个很简单的问题,却很容易出bug.不妨把这个问题当做一道面试题目,我想一定能难道不少的人.今天就给大家说一下在ArrayList循环 ...
- js 遍历集合删除元素
js 遍历集合删除元素 /** * 有效的方式 - 改变下标,控制遍历 */ for (var i = 0; i < arr.length; i++) { if (...) { arr.spli ...
- Java ArrayList正确循环添加删除元素方法及分析
在阿里巴巴Java开发手册中,有这样一条规定: 但是手册中并没有给出具体原因,本文就来深入分析一下该规定背后的思考. 一.foreach循环 foreach循环(Foreach loop)是计算机编程 ...
随机推荐
- java.lang.NoClassDefFoundError: javax/transaction/Synchronization (jUnit测试报错)
测试hibernate 报错原因项目缺少包 在 hibernate 解压目录下找到 jta.jar 文件 往项目中添加该 jar 包,即可解决 添加方法:[右击项目]--> ...
- Nitrous挂VPN
- 交易策略研究 R库
本文在Creative Commons许可证下发布 交易策略研究 R库,直接安装:xts, TTR,quantmod,RTAQ,PerformanceAnalytics,FactorAnalytics ...
- iOS动画原理
1. iOS动画原理 本质:动画对象(这里是UIView)的状态,基于时间变化的反应 分类:可以分为显式动画(关键帧动画和逐帧动画)和隐式动画 关键帧和逐帧总结:关键帧动画的实现方式,只需要修改某个属 ...
- 从百度API中获取天气
网络上看到鱼C的Python入门课程不错,语言风格也引人入胜,想做个实验,这东西到底好不好入门, 就把这个视频推荐给老婆,让他试着学一下,做足了老婆的工作. 这不,这两天她很上心,学得很有成就感,我也 ...
- 【Java基础】Java网络编程基础知识
什么是网络编程 网络编程是通过使用套接字来达到进程间通信目的,那什么是套接字呢?其实套接字是支持TCP/IP的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的 ...
- HDU-4631 Sad Love Story 平面最近点对
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4631 数据是随机的,没有极端数据,所以可以分段考虑,最小值是一个单调不增的函数,然后每次分治算平面最近 ...
- Unity3D实现简单的抽奖程序
下面是具体的代码,注意,我这里用到了NGUI这个插件.大概的原理很简单,就用了2张图片Sprite,同时向下移动,当上面一张图片移动到下面一张图片原来的位置时,就把这2张图片向上移到初始的位置.这时, ...
- Memcached使用笔记
1.linux启动memcached命令 进入到memcached安装目录,可以用whereis memcached查看,默认安装在/usr/bin/目录下 输入以下命令,下面两行任选一行就可以了 m ...
- CSS3之边框图片border-image
CSS3中有关border的属性,还有很多,今天我将为大家介绍一个很好玩的属性——Border-image.有了CSS3之边框图片Border-image,我们可以轻松搞定圆角,轻松搞定很多之前难搞的 ...