1. 简介

本文将介绍三种不同的方式来从 Map 中根据值(value)查找对应的键(key)。我们还会分析每种方案的优劣。

如果你对 Map 接口还不太熟悉,可以先看看这篇 HashMap 详解

2. 迭代法

Java 集合框架中的 Map 接口提供了一个叫 entrySet() 的方法,它会返回一个包含所有键值对的 Set

✅ 思路很简单:遍历这个 entry-set,找到值匹配的那个 entry,然后返回其 key:

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

⚠️ 但要注意,可能存在多个 key 指向同一个 value 的情况。

所以如果你需要找出所有匹配的 key,可以改成这样:

public <K, V> Set<K> getKeys(Map<K, V> map, V value) {
    Set<K> keys = new HashSet<>();
    for (Entry<K, V> entry : map.entrySet()) {
        if (entry.getValue().equals(value)) {
            keys.add(entry.getKey());
        }
    }
    return keys;
}

❌ 缺点是即使在前面几轮就找到了全部结果,它也会继续遍历完整个 map,性能略差。

3. 函数式风格(Java 8+)

有了 Lambda 表达式和 Stream API 后,我们可以写得更优雅一些:

public <K, V> Stream<K> keys(Map<K, V> map, V value) {
    return map
      .entrySet()
      .stream()
      .filter(entry -> value.equals(entry.getValue()))
      .map(Map.Entry::getKey);
}

✅ 返回 Stream 的好处在于灵活性高,调用方可以根据需求决定是要第一个 key 还是全部 key:

Stream<String> keyStream1 = keys(capitalCountryMap, "South Africa");
String capital = keyStream1.findFirst().get();

Stream<String> keyStream2 = keys(capitalCountryMap, "South Africa");
Set<String> capitals = keyStream2.collect(Collectors.toSet());

由于 Stream 是惰性求值的,调用方还能控制实际执行多少次迭代。

4. 使用 Apache Commons Collections

如果某个 Map 要频繁地通过 value 查找 key,每次都遍历一遍显然效率不高。

✅ 更合理的做法是维护一个反向索引的 Map,这样查找就是 O(1) 时间复杂度。

Apache Commons 提供了双向 Map —— BidiMap,可以直接调用 getKey() 方法:

BidiMap<String, String> capitalCountryMap = new DualHashBidiMap<>();
capitalCountryMap.put("Berlin", "Germany");
capitalCountryMap.put("Cape Town", "South Africa");
String capitalOfGermany = capitalCountryMap.getKey("Germany");

⚠️ 注意:BidiMap 强制要求 key 和 value 都是唯一的,即 1:1 映射关系。如果你尝试插入一个 value 已存在的 entry,它会自动删除旧的那个 entry。

❌ 此外,这种做法占用内存更大,因为它要额外保存一份反向映射。

更多关于 BidiMap 的使用细节可参考 这篇教程

5. 使用 Google Guava

Guava 中也提供了类似的双向 Map —— BiMap。它提供了 inverse() 方法用于获取反向 Map:

HashBiMap<String, String> capitalCountryMap = HashBiMap.create();
capitalCountryMap.put("Berlin", "Germany");
capitalCountryMap.put("Cape Town", "South Africa");
String capitalOfGermany = capitalCountryMap.inverse().get("Germany");

⚠️ 和 BidiMap 类似,BiMap 也不允许重复的 value。否则会抛出 IllegalArgumentException

❌ 同样,为了维护反向映射,内存开销也不小。

想深入了解 BiMap 的朋友可以看 这篇教程

6. 总结

本文介绍了几种从 Map 中通过 value 获取 key 的方式,各有优劣:

方式 优点 缺点
迭代法 实现简单 性能差
函数式 灵活、可定制 仍需遍历
BidiMap / BiMap 查询快(O(1)) 内存开销大、限制多

选择哪种方式取决于你的具体场景,比如是否频繁查询、是否允许重复值、是否在意内存占用等。

完整代码可以在 GitHub 上找到:GitHub 项目地址


原始标题:Get the Key for a Value from a Java Map | Baeldung