Java Map 教程

更新于 2025-12-25

Jakob Jenkov 2020-09-21

Java 的 Map 接口(java.util.Map)表示键(key)与值(value)之间的映射关系。更具体地说,Java 的 Map 可以存储键值对(key-value pairs),每个键都关联一个特定的值。一旦将键值对存入 Map,之后就可以仅通过键来查找对应的值。

需要注意的是,Java 的 Map 接口 不是 Collection 接口的子类型,因此其行为与其他集合类型略有不同。

Java Map 的实现类

由于 Map 是一个接口,要使用它,必须实例化一个具体的实现类。Java 集合 API 提供了以下 Map 实现:

  • java.util.HashMap
  • java.util.Hashtable
  • java.util.EnumMap
  • java.util.IdentityHashMap
  • java.util.LinkedHashMap
  • java.util.Properties
  • java.util.TreeMap
  • java.util.WeakHashMap

根据我的经验,最常用的 Map 实现是 HashMapTreeMap

这些 Map 实现在迭代元素时的顺序以及插入和访问元素的时间复杂度(大 O 表示法)方面略有不同:

  • HashMap:将键映射到值,但不保证内部元素的顺序。
  • TreeMap:也映射键和值,但它能保证迭代键或值时的顺序——即按键或值的排序顺序。

通常,HashMap 是两者中速度更快的实现。因此,只要不需要对 Map 中的元素进行排序,就应优先使用 HashMap;否则使用 TreeMap


创建 Map

要创建一个 Java Map,必须实例化一个实现了 Map 接口的类。例如:

Map mapA = new HashMap();
Map mapB = new TreeMap();

泛型 Map(Generic Java Map)

默认情况下,你可以将任意 Object 放入 Map。但从 Java 5 开始,泛型(Generics) 允许你限制 Map 中键和值的类型。例如:

Map<String, MyObject> map = new HashMap<String, MyObject>();

这个 Map 现在只接受 String 类型的键和 MyObject 类型的值。这样,在访问和遍历时就不需要强制类型转换:

for (MyObject anObject : map.values()) {
    // 对 anObject 执行操作...
}

for (String key : map.keySet()) {
    MyObject value = map.get(key);
    // 对 value 执行操作...
}

如果已知 Map 中存储的对象类型,建议在声明和创建 Map 时始终指定泛型类型。这有助于避免插入错误类型的对象,并让阅读代码的人更容易理解 Map 的内容。


向 Java Map 中插入元素

要向 Map 添加元素,调用其 put() 方法。例如:

Map<String, String> map = new HashMap<>();
map.put("key1", "element 1");
map.put("key2", "element 2");
map.put("key3", "element 3");

这三次 put() 调用将字符串值映射到字符串键。之后可以通过键获取对应的值(见下文)。

只能插入对象(Only Objects Can Be Inserted)

只有 Java 对象才能作为键或值存入 Map。如果传入基本类型(如 intdouble 等),Java 会自动装箱(auto-boxing)为对应的包装类。例如:

map.put("key", 123);

这里的 123int 基本类型,但会被自动装箱为 Integer 对象,因为 put() 方法要求参数为 Object 类型。

使用相同键的后续插入(Subsequent Inserts With Same Key)

一个键在 Map 中只能出现一次。也就是说,同一个键不能对应多个值。如果你多次调用 put() 并使用相同的键,最后一次传入的值会覆盖之前的值

null 键(Null Keys)

令人惊讶的是,Java Map 允许使用 null 作为键:

Map map = new HashMap();
map.put(null, "value for null key");

要获取 null 键对应的值,只需将 null 作为参数传给 get() 方法:

Map<String, String> map = new HashMap<>();
String value = map.get(null);

null 值(Null Values)

Map 中的值也可以为 null

map.put("D", null);

之后调用 get("D") 将返回 null

从另一个 Map 插入所有元素

Map 接口提供了 putAll() 方法,可以将另一个 Map 中的所有键值对复制到当前 Map 中(集合论中称为“并集”):

Map<String, String> mapA = new HashMap<>();
mapA.put("key1", "value1");
mapA.put("key2", "value2");

Map<String, String> mapB = new HashMap<>();
mapB.putAll(mapA);

执行后,mapB 将包含 mapA 中的所有条目。注意:putAll() 是单向复制。


从 Java Map 中获取元素

使用 get() 方法并通过键来获取值:

Map<String, String> map = new HashMap<>();
map.put("key1", "value 1");
String element1 = map.get("key1"); // 无需强制转换

获取值或默认值(Get or Default Value)

Map 提供 getOrDefault() 方法,当键不存在时返回指定的默认值:

Map<String, String> map = new HashMap<>();
map.put("A", "1");
map.put("B", "2");
map.put("C", "3");

String value = map.getOrDefault("E", "default value"); // 返回 "default value"

检查 Map 是否包含某个键或值

  • 检查键map.containsKey("123")
  • 检查值map.containsValue("value 1")

遍历 Java Map 的键

有三种常用方式:

1. 使用键的 Iterator

Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
    String key = iterator.next();
    String value = map.get(key);
}

2. 使用 for-each 循环

for (String key : map.keySet()) {
    String value = map.get(key);
}

3. 使用 Stream(Java 8+)

map.keySet().stream().forEach(key -> {
    System.out.println(key + " -> " + map.get(key));
});

遍历 Java Map 的值

通过 values() 方法获取值的集合:

1. 使用值的 Iterator

Iterator<String> iterator = map.values().iterator();
while (iterator.hasNext()) {
    String value = iterator.next();
}

2. 使用 for-each 循环

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

3. 使用 Stream

map.values().stream().forEach(System.out::println);

遍历 Java Map 的条目(Entry)

条目(Entry)即键值对。可通过 entrySet() 获取:

1. 使用 Entry Iterator

Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
    Map.Entry<String, String> entry = iterator.next();
    String key = entry.getKey();
    String value = entry.getValue();
}

2. 使用 for-each 循环

for (Map.Entry<String, String> entry : map.entrySet()) {
    String key = entry.getKey();
    String value = entry.getValue();
}

从 Java Map 中删除条目

  • 删除指定键map.remove("key1");
  • 清空所有条目map.clear();

替换 Map 中的条目

replace() 方法仅在键已存在时才替换值(与 put() 不同):

map.put("key", "val1");
map.replace("key", "val2"); // 成功替换
map.replace("nonexistent", "val3"); // 无效果

获取 Map 的大小和判断是否为空

  • 条目数量int size = map.size();
  • 是否为空boolean empty = map.isEmpty();

Java Map 的函数式操作(Java 8+)

compute()

map.compute("123", (key, value) -> 
    value == null ? null : value.toString().toUpperCase()
);
  • 若 lambda 返回 null,则删除该条目。

computeIfAbsent()

仅当键不存在时才计算并插入值:

map.computeIfAbsent("123", key -> "abc");

computeIfPresent()

仅当键存在时才更新值:

map.computeIfPresent("123", (key, value) -> 
    value.toString().toUpperCase()
);

merge()

合并新旧值:

map.merge("123", "XYZ", (oldValue, newValue) -> oldValue + "-" + newValue);
  • 若键不存在,则插入 "XYZ"
  • 若存在,则合并为 "oldValue-XYZ"

更多信息

有关 Map 的更多功能,请查阅 Java 官方文档

本文重点介绍了最常用的两个操作:增删元素遍历键/值/条目