Java HashMap在遍歷時刪除元素的實現(xiàn)
1. HashMap數(shù)據(jù)結(jié)構(gòu)
jdk是1.8版本
HashMap 線程不安全
ConcurrentHashMap 線程安全
1.1 數(shù)組+單向鏈表+紅黑樹
元素放入hashmap中,放入node節(jié)點中,nodel節(jié)點有四個字段key value next hash,當(dāng)兩個元素的key通過hash算法得到的hash值相同時就會存入單向鏈表中。hashmap初始值是16,負(fù)載因子是0.75,得到閾值是12,當(dāng)元素超過12就會擴(kuò)容,當(dāng)數(shù)組長度超過64并且單向鏈表長度超過8就會將單向鏈表轉(zhuǎn)為紅黑樹,當(dāng)紅黑樹數(shù)據(jù)量小于6就會再轉(zhuǎn)為單向鏈表
jdk1.8 之前 HashMap 由 數(shù)組 + 鏈表 組成,數(shù)組是 HashMap 的主體,鏈表則是主要為了解決哈希沖突(兩個對象調(diào)用的 hashCode 方法計算的哈希值經(jīng)哈希函數(shù)算出來的地址被別的元素占用)而存在的(“拉鏈法”解決沖突)。jdk1.8 以后在解決哈希沖突時有了較大的變化,當(dāng)鏈表長度大于閾值(或者紅黑樹的邊界值,默認(rèn)為 8 )并且當(dāng)前數(shù)組的長度大于 64 時,此時此索引位置上的所有數(shù)據(jù)改為使用紅黑樹存儲。

1.2 指定初始容量,省去多次擴(kuò)容步驟
實際工作中對HashMap數(shù)據(jù)結(jié)構(gòu)的關(guān)注點,我們可以放在擴(kuò)容上;
HashMap初始容量是16,當(dāng)大于這個值,就會擴(kuò)容,每次都是擴(kuò)大成原來的兩倍;
所以,如果我們可以估算出我們的map需要多大的容量,在初始化的時候直接指定初始容量值,這樣就省略了HashMap一次次擴(kuò)容的步驟
1.3 獲取map內(nèi)容:Map.Entry
Map.Entry是Java中Map接口的一個內(nèi)部接口,用于表示Map中的一個實體,即一個鍵值對(key-value對)。它是一個泛型接口,定義為Entry<K,V>,其中K表示鍵的類型,V表示值的類型。
你可以使用Map.Entry來遍歷Map集合,并獲取每個鍵值對的鍵和值。下面是一個示例代碼:
import java.util.HashMap;
import java.util.Map;
public class MapEntryExample {
public static void main(String[] args) {
Map<Integer, String> maps = new HashMap<>();
maps.put(3, "張飛");
maps.put(2, "關(guān)羽");
maps.put(4, "趙云");
maps.put(1, "劉備");
maps.put(5, "馬超");
for (Map.Entry<Integer, String> entry : maps.entrySet()) {
System.out.println("key=" + entry.getKey() + " value=" + entry.getValue());
}
}
}
這段代碼會輸出Map中每個鍵值對的鍵和值:
key=1 value=劉備
key=2 value=關(guān)羽
key=3 value=張飛
key=4 value=趙云
key=5 value=馬超
通過使用Map.Entry,你可以方便地遍歷Map集合并獲取每個鍵值對的鍵和值。
2. 遍歷集合時刪除元素
遍歷集合時刪除元素這種場景建議用迭代器處理 或者 再新建一個集合進(jìn)行存儲
public static void main(String[] args) {
Map<Integer, String> stuMap = new HashMap<>();
stuMap.put(1, "xlsj");
stuMap.put(2, "xinliushijian");
stuMap.put(3, "心流時間");
// A: entrySet()、keySet()、values()方法作用
// key:value 集合
Set<Map.Entry<Integer, String>> stuEntrySet = stuMap.entrySet();
// key 集合
Set<Integer> stuKeySet = stuMap.keySet();
// value 集合
Collection<String> stuValues = stuMap.values();
System.out.println(stuEntrySet); // [1=xlsj, 2=xinliushijian, 3=心流時間]
System.out.println(stuKeySet); // [1, 2, 3]
System.out.println(stuValues); // [xlsj, xinliushijian, 心流時間]
// B: 遍歷集合時刪除元素, 普通for循環(huán)、迭代器不會報錯,其他會報錯,增強(qiáng)for循環(huán)其實也是用到迭代器,
// 集合遍歷時不可以刪除元素,而迭代器可以
// 報錯原因如下modCount != expectedModCount
/* final HashMap.Node<K,V> nextNode() {
HashMap.Node<K,V>[] t;
HashMap.Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
if ((next = (current = e).next) == null && (t = table) != null) {
do {} while (index < t.length && (next = t[index++]) == null);
}
return e;
}*/
// 1.普通for循環(huán)遍歷時可以刪除元素
for (int i = 0; i < stuKeySet.size(); i++) {
if (i == 2) {
stuKeySet.remove(i);
}
}
// 2.for增強(qiáng)循環(huán)遍歷時刪除元素報異常:Exception in thread "main" java.util.ConcurrentModificationException
for (int i : stuKeySet) {
if (i == 2) {
stuKeySet.remove(i);
}
}
// 3.forEach循環(huán)遍歷時刪除元素報異常:Exception in thread "main" java.util.ConcurrentModificationException
stuMap.forEach((k, v) -> {
if (k == 2) {
stuKeySet.remove(k);
}
});
// 4.stream forEach循環(huán)遍歷時刪除元素報異常:Exception in thread "main" java.util.ConcurrentModificationException
stuKeySet.stream().forEach(k -> {
if (k == 2) {
stuKeySet.remove(k);
}
});
// 5.迭代器遍歷時可以刪除元素
Iterator integers = stuEntrySet.iterator();
while (integers.hasNext()) {
Map.Entry<Integer, String> entry = (Map.Entry<Integer, String>) integers.next();
System.out.println(entry.getKey());
if (entry.getKey() == 2) {
integers.remove();
}
}
System.out.println(stuMap);
}
3. computeIfAbsent()方法
key不存在或者value為null時,使用put給定的值
public static void main(String[] args) {
Map<String, List<String>> map = new HashMap<>();
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
map.put("xin", list);
map.put("xi", new ArrayList<>());
map.put("x", null);
// jing這個key不存在或者對應(yīng)的value不存在,則put給的值
List<String> list1 = map.computeIfAbsent("jing",h -> Arrays.asList(new String[]{"DE", "BU", "DE"}));
List<String> list2 = map.computeIfAbsent("xin",h -> Arrays.asList(new String[]{"DE", "BU", "DE"}));
List<String> list3 = map.computeIfAbsent("xi",h -> Arrays.asList(new String[]{"DE", "BU", "DE"}));
List<String> list4 = map.computeIfAbsent("x",h -> Arrays.asList(new String[]{"DE", "BU", "DE"}));
System.out.println(list1);
System.out.println(list2);
System.out.println(list3);
System.out.println(list4);
System.out.println("---------------jing--------------");
System.out.println(map.get("jing"));
map.putIfAbsent("jing1", Arrays.asList(new String[]{"DE1", "BU1", "DE1"}));
System.out.println("---------------jing1--------------");
System.out.println(map.get("jing1"));
}
打印
[DE, BU, DE]
[a, b, c]
[]
[DE, BU, DE]
---------------jing--------------
[DE, BU, DE]
---------------jing1--------------
[DE1, BU1, DE1]
到此這篇關(guān)于Java HashMap在遍歷時刪除元素的實現(xiàn)的文章就介紹到這了,更多相關(guān)Java HashMap遍歷時刪除元素內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring使用@Autowired為抽象父類注入依賴代碼實例
這篇文章主要介紹了Spring使用@Autowired為抽象父類注入依賴代碼實例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-11-11
SpringCloudAlibaba微服務(wù)調(diào)用組件OpenFeign的方法
Feign是Netflix開發(fā)的聲明式、模板化的HTTP客戶端,其靈感來自Retrofit、JAXRS-2.0以及WebSocket,Feign可幫助我們更加便捷、優(yōu)雅地調(diào)用HTTP API,這篇文章主要介紹了SpringCloudAlibaba微服務(wù)調(diào)用組件OpenFeign,需要的朋友可以參考下2024-07-07
基于Springboot執(zhí)行多個定時任務(wù)并動態(tài)獲取定時任務(wù)信息
這篇文章主要為大家詳細(xì)介紹了基于Springboot執(zhí)行多個定時任務(wù)并動態(tài)獲取定時任務(wù)信息,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-04-04
Mybatis不啟動項目直接測試Mapper的實現(xiàn)方法
在項目開發(fā)中,測試單個Mybatis Mapper方法通常需要啟動整個SpringBoot項目,消耗大量時間,本文介紹通過Main方法和Mybatis配置類,快速測試Mapper功能,無需啟動整個項目,這方法使用AnnotationConfigApplicationContext容器2024-09-09

