Map

zhegeMaw發表於2024-08-09

一、獲取key和value

獲取key:map.keySet(),獲取map中所有的key,返回一個Set集合儲存所有的鍵;

獲取value:Map.values()或者map.entrySet()

  • Map.values(),方法用來獲取 Map 集合中的所有value,將值存放在一個Set集合中

  • map.entrySet()✅,同時獲取map的key和value,只需要查詢一次;然後for迴圈key,根據key獲取value

獲取key和value:map.entrySet(),同時查詢map的key和value,只需要查詢一次,然後可for迴圈entry獲取key和value

二、常用map之間的區別和使用場景

2.1. hashMap, hashtable,linkedHashMap,treeMap之間的區別

(1)hashMap: 以鍵值對盡心儲存,執行緒不安全,無序,可以允許一個null鍵和多個null,可以透過鍵直接獲取對應值,所以查詢效率高

(2) concurrentHashMap:

(3) linkedHashMap: 它是hashmap的子集,在繼承hashmap的同時新增了一個排序欄位,記錄插入的順序,透過for迴圈可以有序的輸出

(4) treemap: 它實現了sortedmap,所以可以進行集合排序輸出,預設是透過key進行的升序進行排序,也可以自定義進行排序

(5) hashtable(最好不用): 它也是透過鍵值對進行儲存,無序,但是他是執行緒安全的,絕大多數方法使用synchronized修飾,不允許null鍵和null值,一般用於多執行緒併發情況,但是在最新的程式碼中最好不使用,在單執行緒中使用hashmap效率快,在多執行緒併發下,使用ConcurrentHashMap效率更快

2.2. 使用場景

當程式是單執行緒,且對集合輸出的排序沒有確切要求時使用hashMap

當程式是多執行緒併發情況,並且不需要排序,最好使用ConcurrentHashMap

當程式中需要先進先出時,我們則要使用linkedHashMap

當程式中需要對於集合進行特殊化排序時,我們即可使用TreeMap

對比項

HashMap

ConcurrnetHashMap

HashTable(不用)

執行緒安全

非執行緒安全

執行緒安全

執行緒安全

效率

最高

鍵和值

允許為null

允許為null

都不允許

使用選擇

普通map

需要執行緒安全

2.3 HashMap和HashTable

  • HashMap是非執行緒安全的,HashTable是執行緒安全的(內部的方法基本都經過synchronized修飾,其實是對物件加鎖,鎖住的都是物件整體,當Hashtable的大小增加到一定的時候,效能會急劇下降,因為迭代時需要被鎖定很長的時間)
  • HashMap的鍵和值都允許有null存在,而HashTable則都不行。
  • 因為執行緒安全、雜湊效率的問題,HashMap效率比HashTable的要高(HashTable效率低所以不怎麼使用)。
  • HashMap預設初始化陣列的大小為16,擴容時乘2,使用位運算取得雜湊,效率高於取模;jdk8之後,如果連結串列的長度大於8,這個單向連結串列就會轉換為紅黑樹;如果連結串列長度小於6位,就會從紅黑樹轉換為連結串列。陣列擴容時,擴容的大小是原有陣列的2倍;HashTable為11,擴容時為乘2加1,都是素數和奇數,這樣取模雜湊結果更均勻。

三、ConcurrentHashMap

3.1 執行緒安全

ConcurrentHashMap 的執行緒安全指的是:提供的原子性讀寫操作是執行緒安全的, 也就是put()、get()操作是執行緒安全的。即在ConcurrentHashMap的內部使用CAS保證了更新操作的原子性,在同一時間只有一個執行緒能夠完成對值的更新。

3.2 ConcurrentHashMap為什麼高效?

Hashtable低效主要是因為所有訪問Hashtable的執行緒都爭奪一把鎖。如果容器有很多把鎖,每一把鎖控制容器中的一部分資料,那麼當多個執行緒訪問容器裡的不同部分的資料時,執行緒之前就不會存在鎖的競爭,這樣就可以有效的提高併發的訪問效率。這也正是ConcurrentHashMap使用的分段鎖技術。將ConcurrentHashMap容器的資料分段儲存,每一段資料分配一個Segment(鎖),當執行緒佔用其中一個Segment時,其他執行緒可正常訪問其他段資料。

3.3 方法

  • put()

  • get()

  • size()

  • computeIfAbsent:Value不存在時才計算

  • computeIfPresent:Value存在時才計算

  • compute:計算並更新值

https://wizardforcel.gitbooks.io/modern-java/content/ch6.html

http://blog.tanpeng.net/2017/07/13/map-compute/

3.4 問題

1、get+put操作並非原子操作,會導致執行緒不安全

問題描述:https://blog.csdn.net/weixin_46539949/article/details/121114944

解決:synchronized或者computeIfAbsent

  • 1、synchronized程式碼塊鎖住map(效率低 )
  • 2、使用computeIfAbsent

四、HashMap

4.1方法

  • getOrDefault() 方法獲取指定 key 對應對 value,如果找不到 key ,則返回設定的預設值。語法為hashmap.getOrDefault(Object key, V defaultValue)

五、ImmutableMap

可以更簡潔地建立Map物件並賦值;物件建立後不可變

5.1 特點

1.對不可靠的客戶程式碼庫來說,它使用安全,可以在未受信任的類庫中安全的使用這些物件

2.執行緒安全的:immutable物件在多執行緒下安全,沒有競態條件

3.不需要支援可變性, 可以儘量節省空間和時間的開銷. 所有的不可變集合實現都比可變集合更加有效的利用記憶體 (analysis)

4.可以被使用為一個常量,並且期望在未來也是保持不變的

5.2 使用

1.使用of方法
ImmutableMap.of("a", 1, "b", 2);

2、使用Builder類建立

Map<String,Object> immutableMap = new ImmutableMap.Builder<String,Object>()
    .put("k1","v1")
    .put("k2","v2")
    .build();