在我们平时刷hot100时,HashMap 是非常常见的数据结构。它以“键值对”的形式保存数据,可以根据一个 key 快速找到对应的 value

但是,其方法很多,容易忘。故作此篇来保姆级记录 HashMap 常见的方法。

先举个例子,我们可以使用 HashMap 保存学生姓名和成绩:

HashMap<String, Integer> scores = new HashMap<>(); 
scores.put("小明", 90); 
scores.put("小红", 85);

其中:

小明 → 90
小红 → 85
  • "小明""小红" 是 key。

  • 9085 是 value。

一、创建 HashMap

使用 HashMap 前需要导入:

import java.util.HashMap;

创建一个保存“姓名和成绩”的 HashMap

HashMap<String, Integer> map = new HashMap<>();

尖括号中的类型分别表示:

HashMap<Key的类型, Value的类型>

因此:

HashMap<String, Integer>

表示:

  • key 是 String

  • value 是 Integer

需要注意,Java 泛型不能直接使用基本数据类型:

HashMap<String, int> map; // 错误

应该使用包装类:

HashMap<String, Integer> map; // 正确

二、put():添加或修改数据

1.添加键值对

map.put("小明", 90);
map.put("小红", 85);

此时 Map 中的数据是:

小明 → 90
小红 → 85

HashMap 中的 key 不能重复,但是 value 可以重复。

map.put("小明", 90);
map.put("小红", 90);

两个学生都可以对应成绩 90

2.修改数据

如果 key 已经存在,再次调用 put() 会覆盖原来的 value:

map.put("小明", 90);
map.put("小明", 95);

最终:

小明 → 95

所以,HashMap 没有常用的 set() 方法。添加和修改通常都使用 put()

3.put() 的返回值

put() 会返回这个 key 原来对应的 value:

Integer oldValue = map.put("小明", 100);

如果 "小明" 原来的成绩是 95

oldValue = 95

如果这个 key 原来不存在,则返回 null

三、get():根据 key 获取 value

map.put("小明", 90);
Integer score = map.get("小明");
System.out.println(score);

输出:

90

如果 key 不存在:

Integer score = map.get("小刚");
System.out.println(score);

输出:

null

因此,不要随便使用基本类型接收一个可能不存在的值:

int score = map.get("小刚");

如果 "小刚" 不存在,map.get() 返回 null,而 null 无法自动转换成 int,程序会抛出空指针异常。

可以先判断:

if (map.containsKey("小刚")) {
    int score = map.get("小刚");
}

也可以使用后面要介绍的 getOrDefault()

四、getOrDefault():不存在时返回默认值

语法:

map.getOrDefault(key, 默认值);

它的作用是:

  • key 存在:返回对应的 value。

  • key 不存在:返回指定的默认值。

例如:

map.put("小明", 90);

int score1 = map.getOrDefault("小明", 0);
int score2 = map.getOrDefault("小刚", 0);

System.out.println(score1);
System.out.println(score2);

输出:

90
0

需要注意,getOrDefault() 只会返回默认值,不会将默认值保存到 Map 中。

map.getOrDefault("小刚", 0);

执行后,Map 中依然不存在 "小刚"

统计元素出现次数

getOrDefault() 最常见的应用是统计元素出现次数。

例如,统计字符串中每个字符出现的次数:

String s = "aabac";

HashMap<Character, Integer> countMap = new HashMap<>();

for (char c : s.toCharArray()) {
    countMap.put(c, countMap.getOrDefault(c, 0) + 1);
}

System.out.println(countMap);

结果类似:

{a=3, b=1, c=1}

核心代码是:

countMap.put(c, countMap.getOrDefault(c, 0) + 1);

它可以拆解为:

int oldCount;

if (countMap.containsKey(c)) {
    oldCount = countMap.get(c);
} else {
    oldCount = 0;
}

countMap.put(c, oldCount + 1);

五、containsKey():判断 key 是否存在

boolean result = map.containsKey("小明");

返回值是 boolean

true:key 存在
false:key 不存在

例如:

if (map.containsKey("小明")) {
    System.out.println("找到了小明的成绩");
}

containsKey() 经常与 get() 配合使用:

if (map.containsKey("小明")) {
    System.out.println(map.get("小明"));
}

六、containsValue():判断 value 是否存在

boolean result = map.containsValue(90);

它用于判断 Map 中是否存在某个 value。

例如:

map.put("小明", 90);
map.put("小红", 85);

System.out.println(map.containsValue(90)); // true
System.out.println(map.containsValue(60)); // false

不过,containsValue() 通常比 containsKey() 慢,因为它可能需要遍历所有键值对。

七、remove():删除数据

1.根据 key 删除

map.remove("小明");

执行后,"小明" 对应的整个键值对都会被删除。

remove() 会返回被删除的 value:

Integer oldValue = map.remove("小明");

如果原来存在:

小明 → 90

那么:

oldValue = 90

如果 key 不存在,则返回 null

2.同时匹配 key 和 value

map.remove("小明", 90);

只有 Map 中确实存在:

小明 → 90

才会删除。

这个方法返回 boolean

boolean removed = map.remove("小明", 90);
  • 删除成功:true

  • 没有删除:false

八、putIfAbsent():不存在时才添加

map.putIfAbsent("小明", 90);

含义是:

如果 "小明" 不存在,就添加;如果已经存在,就保留原来的值。

例如:

map.put("小明", 90);
map.putIfAbsent("小明", 100);

System.out.println(map.get("小明"));

输出:

90

原来的 90 不会被覆盖。

它和 put() 的区别是:

map.put("小明", 100);          // 无论是否存在,都会写入
map.putIfAbsent("小明", 100);  // 不存在时才写入

九、replace():存在时才修改

map.replace("小明", 100);

只有 "小明" 已经存在时,才会修改对应的 value。

如果 key 不存在,replace() 不会创建新的键值对。

对比一下:

map.put("小刚", 80);       // 不存在也会添加
map.replace("小李", 70);   // 不存在就不处理

还可以指定旧值:

map.replace("小明", 90, 100);

只有当前数据确实是:

小明 → 90

才会修改成:

小明 → 100

十、size()、isEmpty() 和 clear()

size():获取键值对数量

int size = map.size();

例如:

map.put("小明", 90);
map.put("小红", 85);

System.out.println(map.size());

输出:

2

isEmpty():判断是否为空

if (map.isEmpty()) {
    System.out.println("Map 为空");
}

没有任何键值对时返回 true

clear():清空所有数据

map.clear();

执行后:

map.size();    // 0
map.isEmpty(); // true

十一、遍历 HashMap

1.遍历所有 key

for (String key : map.keySet()) {
    System.out.println(key);
}

2.遍历所有 value

for (Integer value : map.values()) {
    System.out.println(value);
}

3.同时遍历 key 和 value

for (Map.Entry<String, Integer> entry : map.entrySet()) {
    String name = entry.getKey();
    Integer score = entry.getValue();

    System.out.println(name + ":" + score);
}

如果同时需要 key 和 value,通常推荐使用 entrySet()

完整示例:

HashMap<String, Integer> map = new HashMap<>();

map.put("小明", 90);
map.put("小红", 85);

for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println(entry.getKey() + ":" + entry.getValue());
}

输出顺序不一定固定:

小明:90
小红:85

十二、HashMap 的主要特点

1.key 不能重复

map.put("小明", 90);
map.put("小明", 100);

最终只会保留:

小明 → 100

2.value 可以重复

map.put("小明", 90);
map.put("小红", 90);

这是允许的。

3.不保证遍历顺序

HashMap 不保证元素按照插入顺序排列。

如果需要保留插入顺序,可以使用:

LinkedHashMap

如果需要按照 key 排序,可以使用:

TreeMap

4.查询速度快

put()get()containsKey()remove() 的平均时间复杂度通常是:O(1)

所以 HashMap 很适合快速查询、统计次数和建立映射关系。

十三、常用方法总结

方法 作用
put(key, value) 添加或修改键值对
get(key) 获取 key 对应的 value
getOrDefault(key, defaultValue) key 不存在时返回默认值
containsKey(key) 判断 key 是否存在
containsValue(value) 判断 value 是否存在
remove(key) 删除指定 key
putIfAbsent(key, value) key 不存在时才添加
replace(key, value) key 存在时才修改
size() 获取键值对数量
isEmpty() 判断 Map 是否为空
clear() 清空 Map
keySet() 获取所有 key
values() 获取所有 value
entrySet() 获取所有键值对

总结

学习 HashMap 时,可以先重点掌握下面五个方法:

map.put(key, value);
map.get(key);
map.getOrDefault(key, defaultValue);
map.containsKey(key);
map.remove(key);

尤其是统计元素出现次数时,经常会使用:

map.put(key, map.getOrDefault(key, 0) + 1);

可以把 HashMap 简单理解为一本字典:

  • key 是要查询的词。

  • value 是这个词对应的解释。

  • put() 负责添加或修改。

  • get() 负责查询。

  • remove() 负责删除。

  • containsKey() 负责判断某个词是否存在。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐