首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Map 集合核心用法:HashMap、LinkedHashMap、TreeMap 選型指南

     編輯:Java 相關知識

Map<K,V> 是鍵值對集合的核心介面,**鍵唯一、值可重複**。本文聚焦三大主流實作——HashMap、LinkedHashMap、TreeMap——的底層原理、效能特性、選型場景與常見陷阱,並補充 Java 8+ 優化與併發替代方案。

一、三大實作核心對比

特性HashMapLinkedHashMapTreeMap
底層結構陣列 + 鏈表/紅黑樹 (JDK 8)HashMap + 雙向鏈表紅黑樹
順序保證無序(隨機)**插入順序** 或 **存取順序****鍵自然順序** 或 **Comparator**
Null 鍵/值允許 1 個 null key、多個 null value允許**不允許 null key**(拋 NPE),允許 null value
執行緒安全非安全非安全非安全
get/put 複雜度O(1) 平均,O(log n) 最壞 (樹化)O(1)O(log n)
記憶體開銷中高(額外雙向指標)高(樹節點)
典型場景通用緩存、計數、索引LRU 快取、有序配置、JSON 序列化保序範圍查詢、排序字典、NavigableMap 操作

二、HashMap 深度解析(JDK 8+)

1. 核心欄位


transient Node[] table;      // 桶陣列,長度永遠 2 的冪
transient int size;               // 鍵值對數量
int threshold;                    // 擴容門檻 = capacity * loadFactor
final float loadFactor;           // 預設 0.75
int modCount;                     // 結構修改次數,fail-fast 依據

2. 關鍵機制

  • 哈希擴散:hash(key) ^ (hash >>> 16) 混合高低位,減少碰撞。
  • 索引計算:(n - 1) & hash(位運算替代取模,要求 n 為 2 的冪)。
  • 鏈表樹化:桶長度 ≥ TREEIFY_THRESHOLD (8) 且 capacity ≥ MIN_TREEIFY_CAPACITY (64) → 紅黑樹,查詢 O(log n)。
  • 樹退化:桶長度 ≤ UNTREEIFY_THRESHOLD (6) → 還原鏈表。
  • 擴容:容量翻倍,rehash 重新分佈(高位決定新桶:原位或原位 + oldCap)。

3. 常用方法速查


V put(K key, V value)                    // 放入,返回舊值
V get(Object key)                        // 取值
V getOrDefault(Object key, V defaultVal) // 取值或預設 (JDK 8)
V putIfAbsent(K key, V value)            // 僅無鍵時放入
V computeIfAbsent(K key, Function)       // 無鍵則計算並放入(原子性)
V computeIfPresent(K key, BiFunction)    // 有鍵則重新計算
V merge(K key, V value, BiFunction)      // 合併邏輯:新值 + 舊值 → 結果
boolean containsKey(Object key)
boolean containsValue(Object value)
void forEach(BiConsumer)                 // 遍歷

三、LinkedHashMap:有序 Map 的瑞士刀

1. 兩種順序模式

  • 插入順序(預設):new LinkedHashMap<>(),適合保持配置檔、JSON 輸出順序。
  • 存取順序:new LinkedHashMap<>(16, 0.75f, true),**最近最少使用 (LRU) 在頭部**,適合實作快取淘汰。
    
    // LRU 快取範本
    class LRUCache extends LinkedHashMap {
        private final int maxSize;
        LRUCache(int maxSize) { super(maxSize, 0.75f, true); this.maxSize = maxSize; }
        @Override protected boolean removeEldestEntry(Map.Entry eldest) {
            return size() > maxSize; // 超過容量自動移除最久未用
        }
    }
    

四、TreeMap:有序導航大師

1. 自然順序 vs Comparator


// 自然順序:Key 實作 Comparable
TreeMap tm1 = new TreeMap<>(); // 字母序

// 自定義比較器:降序
TreeMap tm2 = new TreeMap<>((a,b) -> b.compareTo(a));

2. NavigableMap 進階操作


Map.Entry firstEntry();           // 最小鍵
Map.Entry lastEntry();            // 最大鍵
Map.Entry lowerEntry(K key);      // strictly < key
Map.Entry floorEntry(K key);      // ≤ key
Map.Entry higherEntry(K key);     // strictly > key
Map.Entry ceilingEntry(K key);    // ≥ key
NavigableMap subMap(K from, boolean incF, K to, boolean incT); // 範圍視圖
NavigableMap headMap(K to, boolean inc); // < to
NavigableMap tailMap(K from, boolean inc); // ≥ from

五、常見陷阱與最佳實踐

  1. 可變鍵導致查無此人:放入後修改鍵物件的 equals/hashCode 相關欄位 → 找不到條目。**鍵必須不可變**(String、Integer、自訂 final 類)。
  2. 自訂類作 Key 必覆寫 equals/hashCode:否則預設比較記憶體位址,邏輯錯誤。
  3. 併發環境禁用 HashMap:死循環(JDK 7 擴容)、資料遺失。
    → ConcurrentHashMap(分段鎖/CAS,高併發讀寫)
    → Collections.synchronizedMap(粗粒度鎖,低併發)
  4. 初始化容量預估:new HashMap<>(expectedSize * 4 / 3 + 1) 避免多次擴容。
  5. 遍歷刪除用 Iterator:
    
    Iterator> it = map.entrySet().iterator();
    while (it.hasNext()) { if (cond) it.remove(); }
    
  6. 序列化:HashMap 實作 Serializable,但 transient table 需自定 writeObject/readObject 重建,大量資料建議改用 JSON/Protobuf。

六、Java 8+ 函數式操作精選


// 合併計數
map.merge(word, 1, Integer::sum);

// 分組統計
Map freq = list.stream()
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

// 過濾
map.entrySet().removeIf(e -> e.getValue() < threshold);

// 轉換
Map upper = map.entrySet().stream()
    .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toUpperCase()));

結語

選 HashMap 做通用高效查找,選 LinkedHashMap 保順序或做 LRU,選 TreeMap 需排序/範圍查詢。牢記**鍵不可變、併發用 ConcurrentHashMap、初始容量預估**,Map 就能穩穩支撐你的業務邏輯。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved