1. 概述
本文将深入探讨 Apache Commons Collections 库中的一个有趣数据结构——BidiMap(双向映射)。它扩展了标准 Map
接口,新增了通过值反向查找键的能力,这种特性在特定场景下非常实用。
2. 依赖配置
使用 BidiMap 前需添加以下依赖。Maven 项目在 pom.xml
中添加:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
Gradle 项目在 build.gradle
中添加:
compile 'org.apache.commons:commons-collections4:4.1'
⚠️ 最新版本请查阅 Maven Central
3. 实现类与实例化
BidiMap 仅定义接口规范,具体实现需关注以下类。核心原则:所有实现类均不允许键或值重复(反转映射时值会变成键,违反 Map 唯一键约束)。
3.1 主流实现对比
实现类 | 底层结构 | 特点 | 适用场景 |
---|---|---|---|
DualHashBidiMap |
双 HashMap |
✅ O(1) 级别的键/值查询 ❌ 需维护两个 Map 实例 |
高频查询且不关心顺序的场景 |
DualLinkedHashBidiMap |
双 LinkedHashMap |
✅ 保留插入顺序 ❌ 性能开销略高于 DualHashBidiMap |
需要遍历顺序的场景 |
TreeBidiMap |
红黑树 | ✅ 键/值自动排序 ✅ 内存占用低 ❌ 查询/插入为 O(log n) |
需要有序遍历的场景 |
DualTreeBidiMap |
双 TreeMap |
✅ 功能同 TreeBidiMap ❌ 性能开销更大(维护两个树结构) |
不推荐(直接用 TreeBidiMap ) |
3.2 实例化方式
所有实现类均可直接替换标准 Map
,简单粗暴地无参构造即可:
BidiMap<String, String> map = new DualHashBidiMap<>(); // 最常用
BidiMap<String, String> orderedMap = new DualLinkedHashBidiMap<>(); // 需要顺序时
4. 核心方法详解
BidiMap 在标准 Map 之上提供了四个关键方法,解决开发中的常见痛点。
4.1 put()
- 智能插入机制
插入键值对时,若值已存在则自动覆盖旧条目,避免重复值导致的冲突:
BidiMap<String, String> map = new DualHashBidiMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
assertEquals(map.size(), 2); // ✅ 成功插入
// 踩坑示例:插入重复值
map.put("key3", "value1"); // 自动移除 key1-value1
assertEquals(map.size(), 2); // ❌ 实际只有 key2-value2 和 key3-value1
4.2 inverseBidiMap()
- 反转映射
一键生成键值互换的新 BidiMap,翻译/字典场景的利器:
BidiMap<String, String> map = new DualHashBidiMap<>();
map.put("China", "中国");
map.put("Japan", "日本");
BidiMap<String, String> reversedMap = map.inverseBidiMap();
assertTrue(reversedMap.containsKey("中国")); // ✅ 反向查询成功
assertEquals(reversedMap.get("日本"), "Japan");
4.3 removeValue()
- 按值删除
突破标准 Map 限制,直接通过值删除条目:
BidiMap<String, String> map = new DualHashBidiMap<>();
map.put("user1", "张三");
map.put("user2", "李四");
map.removeValue("张三"); // 直接删除值对应的条目
assertFalse(map.containsKey("user1")); // ✅ user1 已被移除
4.4 getKey()
- 值反向查键
快速获取值对应的键,避免手动遍历:
BidiMap<String, String> map = new DualHashBidiMap<>();
map.put("id001", "admin");
String key = map.getKey("admin");
assertEquals(key, "id001"); // ✅ 直接获取键
assertNull(map.getKey("nonexistent")); // ❌ 不存在则返回 null
5. 总结
BidiMap 的核心价值在于双向查询能力,特别适合:
- 翻译词典(中英互查)
- ID 映射(如用户名与 ID 互查)
- 配置管理(键值需双向访问的场景)
💡 实战建议:优先使用
DualHashBidiMap
满足大多数需求,仅在需要顺序时选择DualLinkedHashBidiMap
,排序场景用TreeBidiMap
。
完整代码示例见 GitHub 仓库。