一、Map 是干嘛的(一句话本质)
用一个 key,O(1) 找到一个 value
常见场景:
id → 对象code → 配置orgId → List<岗位>parentId → children用户 → 权限集合
二、最常用的 Map 实现(怎么选)
| 类型 | 特点 | 适合场景 |
|---|---|---|
HashMap | 最常用,快 | 99% 业务 |
LinkedHashMap | 保持插入顺序 | 下拉框 / 返回有序 |
TreeMap | 按 key 排序 | 排名 / 范围查询 |
ConcurrentHashMap | 线程安全 | 并发缓存 |
EnumMap | 枚举 key,最快 | 状态机 |
👉 默认:HashMap,用错概率最低
三、Map 的基础用法(必须滚瓜烂熟)
1️⃣ put / get
Map<Long, String> map = new HashMap<>();
map.put(1L, "A");
map.put(2L, "B");
String v = map.get(1L); // AString v2 = map.get(3L); // null
⚠️ get 拿不到返回 null,要判空
2️⃣ containsKey(判断是否存在)
if (map.containsKey(id)) {
...
}
⚠️ 不要用 get != null 判断存在性(value 可能本来就是 null)
3️⃣ 遍历 Map(最推荐)
for (Map.Entry<Long, String> entry : map.entrySet()) {
Long key = entry.getKey();
String value = entry.getValue();
}
不推荐:
for (Long key : map.keySet()) { ... } // 会多一次 get
四、Map 的高级常用写法(工程必会)
4️⃣ computeIfAbsent(分组神器)
场景:orgId → List<岗位>
Map<Long, List<GetPositionVO>> map = new HashMap<>();
map.computeIfAbsent(orgId, k -> new ArrayList<>())
.add(position);
👉 最优雅、最不容易写错
5️⃣ putIfAbsent(只在不存在时放)
map.putIfAbsent(key, value);
等价于:
if (!map.containsKey(key)) {
map.put(key, value);
}
6️⃣ getOrDefault(避免 null)
List<String> list = map.getOrDefault(key, List.of());
⚠️ 注意 List.of() 是不可变的,不能 add
7️⃣ merge(计数 / 累加)
统计出现次数
map.merge(word, 1, Integer::sum);
等价于:
map.put(word, map.getOrDefault(word, 0) + 1);
五、Map + Stream(你现在就在用)
8️⃣ List → Map(最常见)
Map<Long, User> userMap = users.stream()
.collect(Collectors.toMap(
User::getId,
u -> u
));
key 冲突怎么办?
Collectors.toMap(
User::getId,
u -> u,
(a, b) -> a // 冲突时保留第一个
)
9️⃣ List → Map<key, List>(分组)
Map<Long, List<User>> map =
users.stream().collect(Collectors.groupingBy(User::getDeptId));
六、Map 在「树结构」中的经典用法(你正在用)
🔥 10️⃣ 扁平树 → Map(id → node)
Map<Long, OrgPostVO> nodeMap = new HashMap<>();
TreeUtils.flattenTree(tree, nodeMap);
👉 后续挂任何东西,都是 O(1)
🔥 11️⃣ parentId → children(构树核心)
Map<Long, List<Node>> parentMap = new HashMap<>();
for (Node node : nodes) {
parentMap.computeIfAbsent(node.getParentId(), k -> new ArrayList<>())
.add(node);
}
七、Map 的坑(高级但致命)
❌ 1. 用 Map 当 List 用
map.put(0, a);
map.put(1, b);
👉 用 List
❌ 2. key 是可变对象
map.put(user, value);
user.setId(2); // 💥 再也 get 不出来
👉 key 必须是不可变的(Long / String / enum)
❌ 3. HashMap 并发写
HashMap 在多线程下可能死循环
👉 用 ConcurrentHashMap
八、Map 的设计哲学(很重要)
Map 是“关系”的表达
| 关系 | Map 结构 |
|---|---|
| 一对一 | Map<K, V> |
| 一对多 | Map<K, List<V>> |
| 多对一 | Map<V, K> |
| 多对多 | 两个 Map |
你现在的:
orgId → OrgPostVO
positionId → PositionVO
就是典型的 中间表映射模型
九、你这个阶段最该记住的 5 个方法
get
containsKey
computeIfAbsent
getOrDefault
Collectors.toMap / groupingBy