Java Map 使用方法大全(工程级)

22 阅读2分钟

一、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