在Java中初始化一个HashMap

评论 0 浏览 0 2018-08-13

1.概述

在本教程中,我们将学习在Java中初始化HashMap的各种方法。

我们将使用Java 8以及Java 9。

进一步的阅读:

在Java中比较两个HashMaps的情况

使用流来处理地图的工作

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是可变的,但它只对静态的东西有效。因此,条目可以在需要时被添加和删除。

让我们继续测试一下:

@Test
public void givenStaticMap_whenUpdated_thenCorrect() {
    
    MapInitializer.articleMapOne.put(
      "NewArticle1", "Convert array to List");
    
    assertEquals(
      MapInitializer.articleMapOne.get("NewArticle1"), 
      "Convert array to List");  
}

我们也可以用双括号的语法来初始化地图。

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

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

3.使用Java集合

如果我们需要创建一个只有一个条目的单子不可变Map,Collections.singletonMap()就会变得非常有用。

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

请注意,这里的Map是不可变的,如果我们试图添加更多的条目,就会抛出java.lang.UnsupportedOperationException.

我们也可以通过使用Collections.emptyMap()来创建一个不可变的空地图:

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

4.Java 8的方式

在本节中,我们将研究使用 Java 8 Stream API 初始化Map的方法。

4.1.使用 Collectors.toMap()

让我们使用一个Stream的二维String数组,并将它们收集到一个Map中。

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

请注意,这里Map的key和value的数据类型是相同的。

为了让它更通用,让我们拿着Objects 的数组,执行同样的操作。

 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.使用Map.Entry的数据流

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

首先,让我们使用SimpleEntry 实现Entry 接口的方法。

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,因此,任何突变都会导致不支持的操作异常

此外,它们不允许空键或重复键。

现在,如果我们在初始化后需要一个可变的或增长的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

我们已经研究了使用核心Java的方法,让我们继续前进,使用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的例子位于这里

最后更新2023-03-11
0 个评论
标签