如何在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");
        }
    };
}

当前回答

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,否则它不能被视为常量。

其他回答

我已经读了答案,我决定写我自己的地图生成器。请随意复制粘贴并欣赏。

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

/**
 * A tool for easy creation of a map. Code example:<br/>
 * {@code MapBuilder.of("name", "Forrest").and("surname", "Gump").build()}
 * @param <K> key type (inferred by constructor)
 * @param <V> value type (inferred by constructor)
 * @author Vlasec (for http://stackoverflow.com/a/30345279/1977151)
 */
public class MapBuilder <K, V> {
    private Map<K, V> map = new HashMap<>();

    /** Constructor that also enters the first entry. */
    private MapBuilder(K key, V value) {
        and(key, value);
    }

    /** Factory method that creates the builder and enters the first entry. */
    public static <A, B> MapBuilder<A, B> mapOf(A key, B value) {
        return new MapBuilder<>(key, value);
    }

    /** Puts the key-value pair to the map and returns itself for method chaining */
    public MapBuilder<K, V> and(K key, V value) {
        map.put(key, value);
        return this;
    }

    /**
     * If no reference to builder is kept and both the key and value types are immutable,
     * the resulting map is immutable.
     * @return contents of MapBuilder as an unmodifiable map.
     */
    public Map<K, V> build() {
        return Collections.unmodifiableMap(map);
    }
}

编辑:最近,我经常发现公共静态方法,我有点喜欢它。我将它添加到代码中,并使构造函数私有,从而切换到静态工厂方法模式。

EDIT2:甚至最近,我不再喜欢被称为of的静态方法,因为它在使用静态导入时看起来非常糟糕。我将其重命名为mapOf,使其更适合静态导入。

我还没有在任何答案中看到我使用的方法(并且已经逐渐喜欢上了),所以这里是:

我不喜欢使用静态初始化器,因为它们很笨拙, 我不喜欢匿名类,因为它为每个实例创建一个新类。

相反,我更喜欢这样的初始化:

map(
    entry("keyA", "val1"),
    entry("keyB", "val2"),
    entry("keyC", "val3")
);

不幸的是,这些方法不是标准Java库的一部分, 所以你需要创建(或使用)一个实用程序库,它定义了以下方法:

 public static <K,V> Map<K,V> map(Map.Entry<K, ? extends V>... entries)
 public static <K,V> Map.Entry<K,V> entry(K key, V val)

(你可以使用'import static'来避免在方法名前加上前缀)

我发现为其他集合(list、set、sortedSet、sortedMap等)提供类似的静态方法很有用。

它不像json对象初始化那样好,但就可读性而言,这是朝着那个方向迈出的一步。

和往常一样,apache-commons有合适的方法MapUtils。putAll(地图、对象[]):

例如,要创建一个彩色地图:

Map<String, String> colorMap = MapUtils.putAll(new HashMap<String, String>(), new String[][] {
     {"RED", "#FF0000"},
     {"GREEN", "#00FF00"},
     {"BLUE", "#0000FF"}
 });

如果你想要不可修改的映射,最后java 9增加了一个很酷的工厂方法的映射接口。在Set, List中也添加了类似的方法。

Map<String, String> unmodifiableMap = Map。Of ("key1", "value1", "key2", "value2");

JEP 269为Collections API提供了一些方便的工厂方法。该工厂方法不在当前的Java版本(即8)中,但计划在Java 9发行版中使用。

对于Map有两个工厂方法:of和ofEntries。使用of,可以交替传递键/值对。例如,为了创建一个像{age: 27, major: cs}这样的Map:

Map<String, Object> info = Map.of("age", 27, "major", "cs");

目前of有十个重载版本,因此您可以创建一个包含十个键/值对的映射。如果你不喜欢这个限制或交替键/值,你可以使用ofEntries:

Map<String, Object> info = Map.ofEntries(
                Map.entry("age", 27),
                Map.entry("major", "cs")
);

of和ofEntries都将返回一个不可变的Map,因此在构造之后不能更改它们的元素。您可以使用JDK 9 Early Access来尝试这些特性。