Java HashMap 如何正確遍歷并刪除元素的方法小結(jié)
(一)HashMap的遍歷
HashMap的遍歷主要有兩種方式:
第一種采用的是foreach模式,適用于不需要修改HashMap內(nèi)元素的遍歷,只需要獲取元素的鍵/值的情況。
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內(nèi)的元素進(jìn)行修改,并不會對后續(xù)的刪除操作造成影響。
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很有可能會在運(yùn)行時拋出異常。
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());
運(yùn)行上面的代碼,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的元素過程中刪除了當(dāng)前所在元素,下一個待訪問的元素的指針也由此丟失了。
所以,我們改用第二種遍歷方式。
代碼如下:
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());
}
運(yùn)行結(jié)果沒有顯示,表明HashMap中的元素被正確刪除了。
(三)在HashMap的遍歷中刪除元素的特殊情況
上述方法可能足以應(yīng)付多數(shù)的情況,但是如果你的HashMap中的鍵值同樣是一個HashMap,假設(shè)你需要處理的是 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());
}
結(jié)果如下:
1
1
雖然 it.remove(); 被執(zhí)行,但是并沒有真正刪除元素。
原因在于期望刪除的元素的鍵值(即 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)
原因在于,迭代器遍歷時,每一次調(diào)用 next() 函數(shù),至多只能對容器修改一次。上面的代碼則進(jìn)行了兩次修改:一次添加,一次刪除。
既然 java.util.ConcurrentModificationException 異常被拋出了,那么去想辦法拿掉這個異常即可。
最后的最后,我決定棄HashMap轉(zhuǎn)投ConcurrentHashMap。將myHashMap定義為ConcurrentHashMap之后,其它代碼不動。
運(yùn)行結(jié)果如下:
2
1
最終,通過ConcurrentHashMap和一些小技巧的使用,變形實現(xiàn)了對被修改過鍵值的元素的刪除。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
springboot快速集成mybatis-plus的詳細(xì)教程
這篇文章主要介紹了springboot快速集成mybatis-plus的教程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09
SpringBoot詳解整合Spring?Boot?Admin實現(xiàn)監(jiān)控功能
這篇文章主要介紹了SpringBoot整合Spring?Boot?Admin實現(xiàn)服務(wù)監(jiān)控,內(nèi)容包括Server端服務(wù)開發(fā),Client端服務(wù)開發(fā)其中Spring?Boot?Admin還可以對其監(jiān)控的服務(wù)提供告警功能,如服務(wù)宕機(jī)時,可以及時以郵件方式通知運(yùn)維人員,感興趣的朋友跟隨小編一起看看吧2022-07-07
spring?java?動態(tài)獲取consul?K/V的方法
這篇文章主要介紹了spring?java?動態(tài)獲取consul?K/V的相關(guān)資料,主要包括springConsul配置kv路徑以及自動注入consulKV到服務(wù)中,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10
Spring Boot使用Druid進(jìn)行維度的統(tǒng)計和監(jiān)控
這篇文章主要介紹了Spring Boot使用Druid進(jìn)行維度的統(tǒng)計和監(jiān)控,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-04-04

