如何在Java中初始化一个静态Map ?

方法一:静态初始化器 方法二:实例初始化器(匿名子类) 或 还有别的方法吗?

它们各自的优点和缺点是什么?

下面是一个例子来说明这两种方法:

import java.util.HashMap;
import java.util.Map;

public class Test {
    private static final Map<Integer, String> myMap = new HashMap<>();
    static {
        myMap.put(1, "one");
        myMap.put(2, "two");
    }

    private static final Map<Integer, String> myMap2 = new HashMap<>(){
        {
            put(1, "one");
            put(2, "two");
        }
    };
}

当前回答

这是我最喜欢的

不想(或不能)使用Guava的ImmutableMap.of() 或者我需要一个可变Map 或者我需要从JDK9+的Map.of()中超过10个条目限制

public static <A> Map<String, A> asMap(Object... keysAndValues) {
  return new LinkedHashMap<String, A>() {{
    for (int i = 0; i < keysAndValues.length - 1; i++) {
      put(keysAndValues[i].toString(), (A) keysAndValues[++i]);
    }
  }};
}

它非常紧凑,并且忽略了杂散值(即没有值的最终键)。

用法:

Map<String, String> one = asMap("1stKey", "1stVal", "2ndKey", "2ndVal");
Map<String, Object> two = asMap("1stKey", Boolean.TRUE, "2ndKey", new Integer(2));

其他回答

我喜欢匿名类语法;只是代码更少。然而,我发现的一个主要缺点是,您将无法通过远程序列化该对象。您将得到一个关于无法在远程端找到匿名类的异常。

我喜欢匿名类,因为它很容易处理:

public static final Map<?, ?> numbers = Collections.unmodifiableMap(new HashMap<Integer, String>() {
    {
        put(1, "some value");
                    //rest of code here
    }
});
public class Test {
    private static final Map<Integer, String> myMap;
    static {
        Map<Integer, String> aMap = ....;
        aMap.put(1, "one");
        aMap.put(2, "two");
        myMap = Collections.unmodifiableMap(aMap);
    }
}

如果我们声明了多个常量,那么代码将以静态块形式编写,并且以后很难维护。所以最好使用匿名类。

public class Test {

    public static final Map numbers = Collections.unmodifiableMap(new HashMap(2, 1.0f){
        {
            put(1, "one");
            put(2, "two");
        }
    });
}

并且建议对常量使用unmodifiableMap,否则它不能被视为常量。

我更喜欢使用静态初始化式来避免生成匿名类(这将没有进一步的用途),因此我将列出使用静态初始化式进行初始化的技巧。所有列出的解决方案/提示都是类型安全的。

注意:这个问题没有说任何关于使地图不可修改的问题,所以我将把它省略,但要知道可以很容易地使用Collections.unmodifiableMap(map)来完成。

第一个提示

第一个技巧是,你可以对地图进行局部引用,并给它一个简短的名字:

private static final Map<Integer, String> myMap = new HashMap<>();
static {
    final Map<Integer, String> m = myMap; // Use short name!
    m.put(1, "one"); // Here referencing the local variable which is also faster!
    m.put(2, "two");
    m.put(3, "three");
}

第二个提示

第二个技巧是,您可以创建一个helper方法来添加条目;你也可以将这个helper方法设为public,如果你想:

private static final Map<Integer, String> myMap2 = new HashMap<>();
static {
    p(1, "one"); // Calling the helper method.
    p(2, "two");
    p(3, "three");
}

private static void p(Integer k, String v) {
    myMap2.put(k, v);
}

但是这里的helper方法是不可重用的,因为它只能向myMap2添加元素。为了使它可重用,我们可以使映射本身成为helper方法的参数,但这样初始化代码就不会更短了。

第三个技巧

第三个技巧是,您可以创建一个具有填充功能的可重用的类似生成器的helper类。这是一个简单的,10行类型安全的helper类:

public class Test {
    private static final Map<Integer, String> myMap3 = new HashMap<>();
    static {
        new B<>(myMap3)   // Instantiating the helper class with our map
            .p(1, "one")
            .p(2, "two")
            .p(3, "three");
    }
}

class B<K, V> {
    private final Map<K, V> m;

    public B(Map<K, V> m) {
        this.m = m;
    }

    public B<K, V> p(K k, V v) {
        m.put(k, v);
        return this; // Return this for chaining
    }
}

嗯…我喜欢枚举;)

enum MyEnum {
    ONE   (1, "one"),
    TWO   (2, "two"),
    THREE (3, "three");

    int value;
    String name;

    MyEnum(int value, String name) {
        this.value = value;
        this.name = name;
    }

    static final Map<Integer, String> MAP = Stream.of( values() )
            .collect( Collectors.toMap( e -> e.value, e -> e.name ) );
}