系列中的上一篇
当前教程
管理地图内容

系列中的上一篇: 使用地图存储键值对

系列中的下一篇: 使用 Lambda 表达式处理地图值

管理地图内容

 

向地图添加键值对

您可以使用 put(key, value) 在地图中简单地添加键值对。如果键不存在于地图中,则键值对将被简单地添加到地图中。如果存在,则现有值将被替换为新值。

在这两种情况下,put() 方法将返回当前绑定到该键的现有值。这意味着,如果这是一个新键,则调用 put() 将返回 null。

Java SE 8 引入了 putIfAbsent() 方法。此方法也可以向地图添加键值对,但前提是键不存在,并且没有与 null 值关联。这乍一看可能有点令人困惑,但 putIfAbsent() 将用提供的新值替换 null 值。

如果您需要消除地图中的错误 null 值,此方法非常方便。例如,以下代码将因 NullPointerException 而失败,因为您不能自动将 null Integer 拆箱为 int 值。

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

map.put("one", 1);
map.put("two", null);
map.put("three", 3);
map.put("four", null);
map.put("five", 5);

for (int value : map.values()) {
    System.out.println("value = " + value);
}

如果您仔细查看此代码,您会发现 map.values() 是一个 Collection<Integer>。因此,迭代此集合会生成 Integer 的实例。因为您将 value 声明为 int,所以编译器将自动将此 Integer 拆箱为 int 值。如果 Integer 的实例为 null,则此机制将因 NullPointerException 而失败。

您可以使用以下代码修复此地图,该代码将错误的 null 值替换为默认值 -1,该值不会再生成任何 NullPointerException

for (String key : map.keySet()) {
    map.putIfAbsent(key, -1);
}

运行前面的代码将打印以下内容。如您所见,此地图不再包含任何 null 值

value = -1
value = 1
value = -1
value = 3
value = 5

 

从键中获取值

您可以通过简单地调用 get(key) 方法来获取绑定到给定键的值。

Java SE 8 引入了 getOrDefault() 方法,该方法接受一个键和一个默认值,如果键不存在于地图中,则返回该默认值。

让我们在一个示例中看看此方法的实际应用

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

map.put(1, "one");
map.put(2, "two");
map.put(3, "three");

List<String> values = new ArrayList<>();
for (int key = 0; key < 5; key++) {
    values.add(map.getOrDefault(key,"UNDEFINED"));
}

System.out.println("values = " + values);

或者,如果您熟悉流(将在本教程的后面部分介绍)

List<String> values =
    IntStream.range(0, 5)
        .mapToObj(key -> map.getOrDefault(key, "UNDEFINED"))
        .collect(Collectors.toList());

System.out.println("values = " + values);

两段代码都打印出相同的结果

values = [UNDEFINED, one, two, three, UNDEFINED]

 

从地图中删除键

通过调用 remove(key) 方法来删除键值对。此方法将返回绑定到该键的值,因此它可能返回 null

如果您不知道绑定到该键的值,则盲目地从地图中删除键值对可能很危险。因此,Java SE 8 添加了一个重载,它将值作为第二个参数。这次,只有当键值对完全匹配地图中的键值对时,才会删除键值对。

remove(key, value) 方法返回一个布尔值,如果键值对已从地图中删除,则返回 true

 

检查键或值的是否存在

您有两种方法可以检查给定键或给定值的是否存在:containsKey(key)containsValue(value)。如果地图包含给定键或值,则这两个方法都返回 true

 

检查地图的内容

Map 接口还提供了一些方法,这些方法类似于您在 Collection 接口中拥有的方法。这些方法不言自明:isEmpty() 对空地图返回 truesize() 返回键值对的数量,而 clear() 将删除地图的所有内容。

还有一个方法可以将给定地图的内容添加到当前地图中:putAll(otherMap)。如果某些键同时存在于两个地图中,则 otherMap 的值将覆盖此地图的值。

 

获取地图的键、值或条目的视图

您还可以获取定义在地图上的不同集合。

以下示例展示了这三种方法的实际应用

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

map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
map.put(4, "four");
map.put(5, "five");
map.put(6, "six");

Set<Integer> keys = map.keySet();
System.out.println("keys = " + keys);

Collection<String> values = map.values();
System.out.println("values = " + values);

Set<Map.Entry<Integer, String>> entries = map.entrySet();
System.out.println("entries = " + entries);

运行此代码将产生以下结果

keys = [1, 2, 3, 4, 5]
values = [one, two, three, four, five]
entries = [1=one, 2=two, 3=three, 4=four, 5=five]

这些集合是视图,由当前地图支持。对地图所做的任何更改都将反映在这些视图中。

从键集合中删除键

修改这些集合之一也将反映在地图中:例如,从 keySet() 调用返回的集合中删除键,将从地图中删除相应的键值对。

例如,您可以在前面的地图上运行此代码

keys.remove(3);
entries.forEach(System.out::println);

它将产生以下结果

1=one
2=two
4=four
5=five
6=six

从值集合中删除值

删除值并不像看起来那么简单,因为一个值可能在映射中出现多次。在这种情况下,从值集合中删除值只会删除第一个匹配的键值对。

您可以在以下示例中看到这一点。

Map<Integer, String> map =
    Map.ofEntries(
        Map.entry(1, "one"),
        Map.entry(2, "two"),
        Map.entry(3, "three"),
        Map.entry(4, "three")
    );
System.out.println("map before = " + map);
map = new HashMap<>(map);
map.values().remove("three");
System.out.println("map after = " + map);

运行此代码将产生以下结果。

map before = {1=one, 2=two, 3=three, 4=three}
map after  = {1=one, 2=two, 4=three}

如您所见,在本例中,只删除了第一个键值对。您需要小心,因为如果您选择的实现是 HashMap,您无法提前知道将找到哪个键值对。

但是,您无法访问这些集合上的所有操作。例如,您无法向键集或值集合添加元素。如果您尝试这样做,您将收到一个UnsupportedOperationException

如果您需要遍历映射的键值对,那么最好的选择是直接遍历键值对集合。这样做比遍历键集并获取对应值要高效得多。您可以使用以下最佳模式

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

最后更新: 2021 年 9 月 14 日


系列中的上一篇
当前教程
管理地图内容

系列中的上一篇: 使用地图存储键值对

系列中的下一篇: 使用 Lambda 表达式处理地图值