Skip to content

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")); // 10

putIfAbsent:只在不存在时添加

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; // 1

containsKey / 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); // 删除 a

computeIfAbsent:不存在时才计算(懒加载)

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 = 3

merge 的经典应用:词频统计

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+ 的 computemergecomputeIfAbsent 是 HashMap 的「高阶玩法」,能让代码更简洁。


相关链接

基于 VitePress 构建