静态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

测试用例验证可变性:

@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");
}};

强烈不推荐:每次使用都会创建匿名类,持有外部对象引用,可能导致内存泄漏

使用Java集合工具类

当需要创建单条目的不可变Map时,Collections.singletonMap() 是最佳选择:

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

⚠️ 注意:此Map不可变,尝试添加条目会抛出 UnsupportedOperationException

创建空不可变Map:

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

Java 8的方式

使用Collectors.toMap()

通过Stream处理二维数组并收集为Map:

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

更通用的Object数组实现:

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

使用Map.Entry的Stream

使用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));

使用不可变条目实现:

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));

初始化不可变Map

通过collectingAndThen包装为不可变Map:

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));

性能警告:Stream初始化会产生大量临时对象,性能开销大

Java 9的方式

使用Map.of()

Java 9新增工厂方法,支持0-10个键值对:

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个键值对,不可变,不允许null或重复键

使用Map.ofEntries()

无键值对数量限制的工厂方法:

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<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")));

使用Guava库

创建不可变Map:

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

创建可变Map:

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

ImmutableMap.of()支持最多5个键值对的重载版本:

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

结论

本文探讨了Java中初始化Map的多种方式,包括空Map、单例Map、可变Map和不可变Map的创建技巧。Java 9的工厂方法带来了显著改进,大幅简化了初始化过程。开发者应根据实际场景选择合适的方式,避免踩坑(如双花括号语法的内存泄漏问题)。

示例源码参见 GitHub项目
Java 9示例位于此处
Guava示例参考这里


原始标题:Initialize a HashMap in Java | Baeldung