概述

本教程将探讨如何在Java中处理嵌套的HashMap。我们将学习如何创建、比较它们,以及如何向内层地图添加和删除记录。

嵌套HashMap的应用场景

嵌套HashMap非常适合存储JSON或类似JSON的结构,其中对象嵌套在其他对象中。例如,类似以下结构的JSON:

{
  "d5a46b57-7cb1-441a-a743-b6507a6b3a5c": {
    // 其他嵌套数据
  }
}

在这种情况下,嵌套HashMap是理想的选择。一般来说,当我们需要在一个对象中嵌套另一个对象时,都可以使用它们。

创建HashMap

创建HashMap的方法有很多种,比如手动构造、使用流(Streams)和分组函数等。HashMap可以包含基本类型或对象。

3.1 使用put()方法

我们可以通过手动创建内层地图,然后使用put方法插入到外层地图中来构建嵌套HashMap

Map<String, Map<String, String>> nestedMap = new HashMap<>();
nestedMap.put("key1", new HashMap<>());
nestedMap.get("key1").put("innerKey", "innerValue");

我们可以用以下代码进行测试:

nestedMap.get("key1").get("innerKey"); // 返回 "innerValue"

3.2 使用流(Streams)

如果我们有一个想要转换为MapList,我们可以创建一个流,然后使用Collectors.toMap方法将其转换为Map。这里有两个例子:一个是包含字符串内层Map的,另一个是具有整数和对象值的Map

第一个例子中,Employee对象内嵌有Address对象,我们构建了一个嵌套HashMap

List<Employee> employees = ...;
Map<String, Employee> employeeMap = employees.stream()
    .collect(Collectors.toMap(Employee::getId, e -> new HashMap<>(e.getAddress().entrySet())));

第二个例子中,我们构建了一个<Employee id, Address id, Address object>类型的对象:

Map<Integer, Map<Integer, Address>> addressMap = ...;

遍历嵌套HashMap

遍历嵌套HashMap与遍历普通或非嵌套的HashMap没有区别。嵌套Map与普通Map的主要区别在于嵌套HashMap的值是Map类型:

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

比较嵌套HashMap

在Java中,有许多方法可以比较HashMap。我们可以使用equals()方法进行比较。默认实现会逐个比较值。

如果改变内层地图的内容,平等检查会失败。对于用户自定义对象,如果每次内层对象都是新实例,那么平等检查也会失败。同样,如果改变外层Map的内容,平等检查也将失败:

nestedMap1.equals(nestedMap2); // 返回 false

对于值为用户自定义对象的Map,我们需要使用比较HashMap文章中提到的一种方法自定义相等性方法,否则检查将失败:

nestedMap1.equalsUsingCustomComparator(nestedMap2); // 自定义比较逻辑

如果两个地图相同,那么平等检查将成功。对于用户自定义地图,如果所有相同的对象都被移动到另一个地图中,平等检查也将成功:

nestedMap1.equalsUsingCustomComparator(sameObjectsMap); // 返回 true

向嵌套HashMap添加元素

要向嵌套HashMap的内层Map添加元素,首先需要获取它。我们可以使用get()方法获取内层对象,然后对内层Map对象使用put()方法插入新值:

Map<String, Map<String, String>> nestedMap = ...;
nestedMap.get("outerKey").put("innerKey", "newValue");

如果要向外层Map添加条目,还需要提供正确的内层Map条目:

Map<String, Map<String, String>> outerMap = ...;
outerMap.put("outerKey", new HashMap<>());
outerMap.get("outerKey").put("innerKey", "innerValue");

从嵌套HashMap删除记录

要从内层Map中删除记录,首先需要获取它,然后使用remove()方法删除。如果内层Map中只有一个值,那么删除后将留下一个null对象作为值:

Map<String, Map<String, String>> nestedMap = ...;
nestedMap.get("outerKey").remove("innerKey"); // 如果只有一个值,将变为 null
nestedMap.get("outerKey").isEmpty(); // 如果内层为空,返回 true

如果从外层Map中删除记录,Java会同时删除内外层的记录,因为内层Map是外层Map的“值”:

nestedMap.remove("outerKey"); // 外层和内层都会被删除

展平嵌套HashMap

嵌套HashMap的替代方案是使用组合键。组合键通常将嵌套结构的两个键以点分隔。例如,组合键可能是Donut.1Donut.2等。我们可以将嵌套的Map结构转换为单一Map结构,即“展平”:

Map<String, String> flattenedMap = new HashMap<>();
flattenedMap.put("Donut.1", "value1");
flattenedMap.put("Donut.2", "value2");

组合键方法克服了嵌套HashMap带来的额外内存存储劣势。然而,组合键方法在扩展性方面并不理想。

结论

在这篇文章中,我们了解了如何创建、比较、更新和展平嵌套HashMap。如往常一样,代码可以在GitHub上找到。