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和一些小技巧的使用,变形实现了对被修改过键值的元素的删除。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。