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

Java HashMap 反向查找:根據 Value 獲取所有對應 Key 的最佳實踐

     編輯:Java 相關知識

場景痛點

HashMap 設計為 Key → Value 單向映射,原生不支持按 Value 反查 Key。實際開發中常遇到「一個 Value 對應多個 Key」(如權限碼→用戶 ID)需反查場景。

方案對比

方案優點缺點適用場景
遍歷 entrySet()無額外內存,代碼簡單O(n) 時間複雜度,頻繁查詢性能差數據量小、查詢頻率低
維護雙向 Map (Guava BiMap 或兩個 Map)O(1) 查詢雙倍內存,插入刪除需同步維護頻繁雙向查詢、數據量中等
MultiMap (Guava ArrayListMultimap)原生支持一鍵多值引入第三方依賴一對多映射、需刪除單個映射
值唯一時用 BiMap強制 1:1,自動反向索引值重複會拋異常業務保證 Value 唯一

核心代碼:遍歷 entrySet 通用實現

import java.util.*;

public class MapValueGetKey {

    /**
     * 根據 value 反查所有匹配的 key
     * @param map 目標 Map
     * @param value 待查值
     * @param <K> Key 類型
     * @param <V> Value 類型
     * @return 匹配的 key 列表,無匹配返回空列表
     */
    public static <K, V> List<K> getKeysByValue(Map<K, V> map, V value) {
        List<K> keys = new ArrayList<>();
        if (map == null || value == null) return keys;

        for (Map.Entry<K, V> entry : map.entrySet()) {
            if (Objects.equals(entry.getValue(), value)) {
                keys.add(entry.getKey());
            }
        }
        return keys;
    }

    public static void main(String[] args) {
        Map<Integer, String> map = new HashMap<>();
        map.put(1, "A");
        map.put(2, "A");
        map.put(3, "B");
        map.put(4, "A");
        map.put(5, "C");

        String target = "A";
        List<Integer> keys = getKeysByValue(map, target);
        System.out.println("Value '" + target + "' 對應的 Keys: " + keys);
        // 輸出: [1, 2, 4]
    }
}

進階:高性能雙向索引封裝

若系統高頻反查,建議封裝雙 Map 結構:

public class BiHashMap<K, V> {
    private final Map<K, V> keyToValue = new HashMap<>();
    private final Map<V, Set<K>> valueToKeys = new HashMap<>();

    public void put(K key, V value) {
        // 移除舊映射
        V oldVal = keyToValue.get(key);
        if (oldVal != null) {
            Set<K> set = valueToKeys.get(oldVal);
            if (set != null) set.remove(key);
        }
        // 建立新映射
        keyToValue.put(key, value);
        valueToKeys.computeIfAbsent(value, k -> ConcurrentHashMap.newKeySet()).add(key);
    }

    public V get(K key) { return keyToValue.get(key); }

    public Set<K> getKeys(V value) {
        return valueToKeys.getOrDefault(value, Collections.emptySet());
    }

    public void remove(K key) {
        V val = keyToValue.remove(key);
        if (val != null) {
            Set<K> set = valueToKeys.get(val);
            if (set != null) set.remove(key);
        }
    }
}

避坑指南

  • Null 值:HashMap 允許一個 null key、多個 null value,反查時需用 Objects.equals 防 NPE。
  • 并發場景:多線程環境用 ConcurrentHashMap + 上述雙 Map 邏輯,或直接用 Guava Multimap 的線程安全實現。
  • 值對象 equals/hashCode:自定義 Value 類必須正確重寫 equals 和 hashCode,否則反查失效。

總結

偶爾反查用 entrySet() 遍歷最簡潔;高頻雙向查詢請自維護雙 Map 或引入 Guava Multimap/BiMap。選型核心:查詢頻率 vs 內存開銷 vs 維護成本。

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