HashMap 常用方法:从 CRUD 到高级操作
方法分类地图
HashMap 有 20+ 方法,但可以归为几大类:
HashMap 方法
│
├── 增删改:put, putIfAbsent, putAll, remove, clear
│
├── 查询:get, getOrDefault, containsKey, containsValue, size, isEmpty
│
├── 替换:replace, replaceAll
│
├── 计算:compute, computeIfAbsent, computeIfPresent, merge
│
└── 视图:keySet, values, entrySet, forEach增删改:最基础的操作
put:添加或覆盖
java
Map<String, Integer> map = new HashMap<>();
map.put("apple", 1);
map.put("banana", 2);
// key 已存在,覆盖旧值,返回旧值
Integer old = map.put("apple", 10);
System.out.println(old); // 1
System.out.println(map.get("apple")); // 10putIfAbsent:只在不存在时添加
java
Map<String, Integer> map = new HashMap<>();
map.put("apple", 1);
map.putIfAbsent("apple", 100); // 返回旧值 1,不覆盖
map.putIfAbsent("banana", 2); // 返回 null,添加成功remove:删除
java
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
// 按 key 删除,返回被删的 value
Integer removed = map.remove("a");
System.out.println(removed); // 1
// 按 key+value 删除(必须都匹配才删)
map.put("b", 2);
boolean deleted = map.remove("b", 2); // true
boolean failed = map.remove("b", 99); // false(value 不匹配)查询:读数据的方式
get:获取 value
java
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
Integer value = map.get("a"); // 1
Integer missing = map.get("z"); // null(key 不存在)getOrDefault:安全获取(推荐)
java
// ❌ 不安全:可能 NPE
Integer value = map.get("z");
int result = value + 1; // NullPointerException!
// ✅ 安全:不存在返回默认值
int result = map.getOrDefault("z", 0) + 1; // 1containsKey / containsValue
java
map.put("a", 1);
map.containsKey("a"); // true
map.containsKey("z"); // false
map.containsValue(1); // true
map.containsValue(99); // false注意:
containsValue时间复杂度是 O(n),因为要遍历所有 value。慎用。
替换:更新现有数据
replace:替换 value
java
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
// 替换 key 的 value(key 不存在则不操作)
Integer old = map.replace("a", 10);
System.out.println(old); // 1
// 条件替换:只有 value 匹配才替换
boolean success = map.replace("a", 10, 20); // true(当前是 10)
boolean failed = map.replace("a", 99, 20); // false(当前是 20,不是 99)replaceAll:批量替换
java
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
// 所有 value 翻倍
map.replaceAll((k, v) -> v * 2);
// {a=2, b=4}JDK 8+ 高级操作:计算与合并
compute:重新计算 value
java
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
// 重新计算 key 对应的 value
// key 存在:biFunction(key, oldValue)
map.compute("a", (k, v) -> v + 10); // a = 1 + 10 = 11
// key 不存在:biFunction(key, null)
map.compute("c", (k, v) -> v == null ? 1 : v); // c = 1
// 返回 null:删除该 entry
map.compute("a", (k, v) -> null); // 删除 acomputeIfAbsent:不存在时才计算(懒加载)
java
Map<String, List<String>> map = new HashMap<>();
// ❌ 传统写法:每次都要检查
List<String> list = map.get("key");
if (list == null) {
list = new ArrayList<>();
map.put("key", list);
}
list.add("value");
// ✅ 优雅写法:不存在时才创建
map.computeIfAbsent("key", k -> new ArrayList<>()).add("value");computeIfPresent:存在时才计算
java
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
// 只有 key 存在且 value 不为 null 时才计算
map.computeIfPresent("a", (k, v) -> v + 10); // a = 11
map.computeIfPresent("z", (k, v) -> v + 10); // 返回 null,不操作merge:合并 value
java
Map<String, Integer> map = new HashMap<>();
map.put("apple", 1);
map.put("banana", 2);
// key 存在:合并两个 value
map.merge("apple", 5, Integer::sum); // apple = 1 + 5 = 6
// key 不存在:直接设置为 value
map.merge("cherry", 3, Integer::sum); // cherry = 3merge 的经典应用:词频统计
java
Map<String, Integer> wordCount = new HashMap<>();
for (String word : text.split("\\s+")) {
// 累加计数
wordCount.merge(word, 1, Integer::sum);
// 等价于:
// wordCount.put(word, wordCount.getOrDefault(word, 0) + 1);
}视图与遍历
keySet / values / entrySet
java
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
// keySet:所有 key
Set<String> keys = map.keySet();
// values:所有 value
Collection<Integer> vals = map.values();
// entrySet:所有键值对
Set<Map.Entry<String, Integer>> entries = map.entrySet();重要:keySet/values/entrySet 返回的是视图,不是副本。对它们的修改会影响原 Map。
java
// 通过 keySet 删除元素
map.keySet().removeIf(k -> k.equals("a")); // 删除 key="a"forEach:遍历(推荐)
java
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
// JDK 8+ 推荐
map.forEach((k, v) -> System.out.println(k + ": " + v));遍历 entry 并修改 value
java
// ✅ 正确:通过 entry 修改 value
for (Map.Entry<String, Integer> entry : map.entrySet()) {
if (entry.getValue() > 10) {
entry.setValue(entry.getValue() * 2);
}
}
// ❌ 错误:通过 key 获取再修改
for (String key : map.keySet()) {
map.put(key, map.get(key) * 2); // 可能触发扩容、覆盖问题
}Map.Entry:键值对的表示
java
Map<String, Integer> map = Map.of("a", 1, "b", 2);
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey(); // 获取 key
Integer value = entry.getValue(); // 获取 value
entry.setValue(value * 10); // ⚠️ 只对可变 Map 有效
System.out.println(key + "=" + value);
}按 value 排序
java
Map<String, Integer> map = new HashMap<>();
map.put("apple", 3);
map.put("banana", 1);
map.put("cherry", 2);
// 按 value 升序
List<Map.Entry<String, Integer>> sorted = map.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toList());
// [banana=1, cherry=2, apple=3]
// 按 value 降序
List<Map.Entry<String, Integer>> desc = map.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.collect(Collectors.toList());方法对比表
| 场景 | 推荐方法 | 说明 |
|---|---|---|
| 添加/覆盖 | put | 返回旧 value |
| 不存在才添加 | putIfAbsent | 原子操作 |
| 安全获取 | getOrDefault | 避免 NPE |
| 计数累加 | merge(key, 1, Integer::sum) | 最简洁 |
| 懒加载缓存 | computeIfAbsent | 不存在才创建 |
| 条件更新 | replace(key, oldVal, newVal) | 原子 CAS |
| 批量更新 | replaceAll((k, v) -> ...) | 一行搞定 |
总结
| 要点 | 说明 |
|---|---|
getOrDefault | 代替 get + 空值判断,避免 NPE |
computeIfAbsent | 懒加载缓存的最佳选择 |
merge | 累加/合并的最简洁写法 |
| 视图修改 | keySet/values/entrySet 的修改影响原 Map |
| 按 value 排序 | 用 Stream 或手动排序 entrySet |
一句话:JDK 8+ 的
compute、merge、computeIfAbsent是 HashMap 的「高阶玩法」,能让代码更简洁。
