1. 概述

本文,我们将学习如何在 Java 中初始化 HashMap ,提供多种方法,包括Java 8 和 Java 9。

2. 静态代码块初始化 HashMap

方法一,我们可以在静态代码块初始化 HashMap

public static Map<String, String> articleMapOne;
static {
    articleMapOne = new HashMap<>();
    articleMapOne.put("ar01", "Intro to Map");
    articleMapOne.put("ar02", "Some article");
}

我们也可以使用双括号语法初始化 Map:

Map<String, String> doubleBraceMap  = new HashMap<String, String>() {{
    put("key1", "value1");
    put("key2", "value2");
}};

注意,我们应避免使用这种初始化技术,因为它在每次使用时都会创建一个匿名额外类,持有对封闭对象的隐藏引用,并可能导致内存泄漏问题。

3. 使用 Java Collections

使用 *Collections.singletonMap()*,我们可以创建一个包含单条记录且不可变 Map:

public static Map<String, String> createSingletonMap() {
    return Collections.singletonMap("username1", "password1");
}

注意,这里的 Map 是不可变的,如果我们尝试添加更多元素,它会抛出 java.lang.UnsupportedOperationException.

我们可以使用 Collections.emptyMap() 创建一个不可变的空 Map:

Map<String, String> emptyMap = Collections.emptyMap();

4. Java 8 方式

在这一节中,让我们看看如何使用 Java 8 Stream API 初始化 Map。

4.1. 使用 Collectors.toMap()

创建一个 String 二维数组 Stream,然后collect它们到一个 map:

Map<String, String> map = Stream.of(new String[][] {
  { "Hello", "World" }, 
  { "John", "Doe" }, 
}).collect(Collectors.toMap(data -> data[0], data -> data[1]));

注意,这里的 Map 的键和值的数据类型是相同的。

为了使其更通用,我们改用 Object 类型:

 Map<String, Integer> map = Stream.of(new Object[][] { 
     { "data1", 1 }, 
     { "data2", 2 }, 
 }).collect(Collectors.toMap(data -> (String) data[0], data -> (Integer) data[1]));

结果,我们创建了一个键为 String 类型,值为 Integer 类型的 Map。

4.2. 使用 StreamMap.Entry

这里我们将使用 Map.Entry 的实例。这是另一种方法,其中我们有不同的键和值类型。

首先,让我们使用 Entry 接口的 SimpleEntry 实现:

Map<String, Integer> map = Stream.of(
  new AbstractMap.SimpleEntry<>("idea", 1), 
  new AbstractMap.SimpleEntry<>("mobile", 2))
  .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

现在,让我们使用 SimpleImmutableEntry 实现创建 map:

Map<String, Integer> map = Stream.of(
  new AbstractMap.SimpleImmutableEntry<>("idea", 1),    
  new AbstractMap.SimpleImmutableEntry<>("mobile", 2))
  .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

4.3. 不可变 Map

某些场景下,我们需要初始化一个不可变的 Map。这可以通过将 Collectors.toMap() 包装在 Collectors.collectingAndThen() 中来完成:

Map<String, String> map = Stream.of(new String[][] { 
    { "Hello", "World" }, 
    { "John", "Doe" },
}).collect(Collectors.collectingAndThen(
    Collectors.toMap(data -> data[0], data -> data[1]), 
    Collections::<String, String> unmodifiableMap));

请注意,我们应避免使用 Streams 进行初始化,因为它可能会导致巨大的性能开销,并且仅仅为了初始化 Map 就会创建大量垃圾对象。

5. Java 9 方式

Java 9 在 Map 接口中提供了各种工厂方法,简化了不可变 map 的创建和初始化。

让我们看看这些工厂方法。

5.1. Map.of()

这个工厂方法不接受参数,接受单个参数,和可变参数:

Map<String, String> emptyMap = Map.of();
Map<String, String> singletonMap = Map.of("key1", "value");
Map<String, String> map = Map.of("key1","value1", "key2", "value2");

注意,这个方法只支持最多 10 对键值对。

5.2. Map.ofEntries()

它与 Map.of() 类似,但没有键值对数量的限制:

Map<String, String> map = Map.ofEntries(
  new AbstractMap.SimpleEntry<String, String>("name", "John"),
  new AbstractMap.SimpleEntry<String, String>("city", "budapest"),
  new AbstractMap.SimpleEntry<String, String>("zip", "000000"),
  new AbstractMap.SimpleEntry<String, String>("home", "1231231231")
);

注意,这些工厂方法创建不可变的 map,因此任何修改都会导致 UnsupportedOperationException

此外,它们不允许使用 null 键或重复的键。

现在,如果我们需要一个在初始化后可变的或增长的 map,我们可以创建任何 Map 接口的实现,并将这些不可变的 map 传递给构造函数:

Map<String, String> map = new HashMap<String, String> (
  Map.of("key1","value1", "key2", "value2"));
Map<String, String> map2 = new HashMap<String, String> (
  Map.ofEntries(
    new AbstractMap.SimpleEntry<String, String>("name", "John"),    
    new AbstractMap.SimpleEntry<String, String>("city", "budapest")));

6. 使用 Guava

让我们看看如何使用 Guava 库初始化 map:

Map<String, String> articles 
  = ImmutableMap.of("Title", "My New Article", "Title2", "Second Article");

这将创建一个不可变的 map,要创建一个可变的 map:

Map<String, String> articles 
  = Maps.newHashMap(ImmutableMap.of("Title", "My New Article", "Title2", "Second Article"));

方法 ImmutableMap.of() 也有重载版本,可以接受多达 5 对键值参数。这是一个带有 2 对参数的示例:

ImmutableMap.of("key1", "value1", "key2", "value2");

7. 结论

在这篇文章中,我们探索了初始化 Map 的各种方法,特别是创建空、单例、不可变和可变的 map。 我们可以看到,自 Java 9 以来,这方面有了很大的改进。

一如既往,示例源代码位于 Github 项目。Java 9 示例位于 这里,Guava 示例 这里


» 下一篇: 为WildFly增加堆内存