如何在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方法初始化一个静态的、不可变的映射:

static final Map<Integer, String> MY_MAP = ImmutableMap.of(
    1, "one",
    2, "two"
);

正如您所看到的,它非常简洁(因为ImmutableMap中方便的工厂方法)。

如果你想让映射有5个以上的条目,你不能再使用ImmutableMap.of()。相反,尝试ImmutableMap.builder():

static final Map<Integer, String> MY_MAP = ImmutableMap.<Integer, String>builder()
    .put(1, "one")
    .put(2, "two")
    // ... 
    .put(15, "fifteen")
    .build();

要了解更多关于Guava的不可变集合实用程序的好处,请参阅Guava用户指南中的不可变集合解释。

(一个子集)Guava过去被称为谷歌集合。如果您还没有在Java项目中使用这个库,我强烈建议您尝试一下!正如其他SO用户所认同的那样,Guava已经迅速成为Java最流行和最有用的免费第三方库之一。(如果你是新手,在这个链接后面有一些很好的学习资源。)


更新(2015):至于Java 8,嗯,我仍然会使用Guava方法,因为它比其他任何方法都要干净得多。如果不希望依赖于Guava,可以考虑使用普通的init方法。如果你问我,使用二维数组和流API的黑客是非常丑陋的,如果你需要创建一个键和值不相同类型的Map(如Map<Integer, String>在问题中),就会变得更加丑陋。

至于Guava的未来,Louis Wasserman早在2014年就说过,2016年又宣布Guava 21将需要并适当支持Java 8。


更新(2016):正如Tagir Valeev所指出的,Java 9将通过为集合添加方便的工厂方法,最终使这一工作只使用纯JDK即可完成:

static final Map<Integer, String> MY_MAP = Map.of(
    1, "one", 
    2, "two"
);

其他回答

第二个方法的一个优点是,你可以用Collections.unmodifiableMap()来包装它,以确保以后不会更新集合:

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

 // later on...

 CONSTANT_MAP.put(3, "three"); // going to throw an exception!

在这种情况下,我绝不会创建匿名子类。静态初始化器同样有效,如果你想让映射不可修改,例如:

private static final Map<Integer, String> MY_MAP;
static
{
    Map<Integer, String>tempMap = new HashMap<Integer, String>();
    tempMap.put(1, "one");
    tempMap.put(2, "two");
    MY_MAP = Collections.unmodifiableMap(tempMap);
}

这一个使用Apache common -lang,它很可能已经在你的类路径上了:

Map<String, String> collect = Stream.of(
        Pair.of("hello", "world"),
        Pair.of("abc", "123"),
        Pair.of("java", "eight")
).collect(Collectors.toMap(Pair::getKey, Pair::getValue));

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

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对象初始化那样好,但就可读性而言,这是朝着那个方向迈出的一步。