如何在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 abstract class Shape {

    public static final String COLOR_KEY = "color_key";
    public static final String OPAQUE_KEY = "opaque_key";

    private final String color;
    private final Boolean opaque;

    /**
     * Initializing constructor - note no default constructor.
     *
     * @param properties a collection of Shape properties
     */
    public Shape(Map<String, Object> properties) {
        color = ((String) properties.getOrDefault(COLOR_KEY, "black"));
        opaque = (Boolean) properties.getOrDefault(OPAQUE_KEY, false);
    }

    /**
     * Color property accessor method.
     *
     * @return the color of this Shape
     */
    public String getColor() {
        return color;
    }

    /**
     * Opaque property accessor method.
     *
     * @return true if this Shape is opaque, false otherwise
     */
    public Boolean isOpaque() {
        return opaque;
    }
}

以及这个类的具体实现——但它想要/需要一个默认构造函数:

public class SquareShapeImpl extends Shape {

    private static final Map<String, Object> DEFAULT_PROPS = new HashMap<>();

    static {
        DEFAULT_PROPS.put(Shape.COLOR_KEY, "yellow");
        DEFAULT_PROPS.put(Shape.OPAQUE_KEY, false);
    }

    /**
     * Default constructor -- intializes this square to be a translucent yellow
     */
    public SquareShapeImpl() {
        // the static initializer was useful here because the call to 
        // this(...) must be the first statement in this constructor
        // i.e., we can't be mucking around and creating a map here
        this(DEFAULT_PROPS);
    }

    /**
     * Initializing constructor -- create a Square with the given
     * collection of properties.
     *
     * @param props a collection of properties for this SquareShapeImpl
     */
    public SquareShapeImpl(Map<String, Object> props) {
        super(props);
    }
}

然后要使用这个默认构造函数,只需执行以下操作:

public class StaticInitDemo {

    public static void main(String[] args) {

        // create a translucent, yellow square...
        Shape defaultSquare = new SquareShapeImpl();

        // etc...
    }
}

其他回答

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

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

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

这里是算盘常用的代码

Map<Integer, String> map = N.asMap(1, "one", 2, "two");
// Or for Immutable map 
ImmutableMap<Integer, String> = ImmutableMap.of(1, "one", 2, "two");

声明:我是普通算盘的开发者。

也许它是有趣的检查谷歌集合,例如,他们在他们的网页上的视频。它们提供了各种初始化映射和集合的方法,也提供了不可变的集合。

更新:这个库现在被命名为Guava。

下面是一个Java 8单行静态映射初始化器:

private static final Map<String, String> EXTENSION_TO_MIMETYPE =
    Arrays.stream(new String[][] {
        { "txt", "text/plain" }, 
        { "html", "text/html" }, 
        { "js", "application/javascript" },
        { "css", "text/css" },
        { "xml", "application/xml" },
        { "png", "image/png" }, 
        { "gif", "image/gif" }, 
        { "jpg", "image/jpeg" },
        { "jpeg", "image/jpeg" }, 
        { "svg", "image/svg+xml" },
    }).collect(Collectors.toMap(kv -> kv[0], kv -> kv[1]));

编辑:要初始化一个Map<Integer, String>,就像问题中那样,你需要这样的东西:

static final Map<Integer, String> MY_MAP = Arrays.stream(new Object[][]{
        {1, "one"},
        {2, "two"},
}).collect(Collectors.toMap(kv -> (Integer) kv[0], kv -> (String) kv[1]));

编辑(2):i_am_zero有一个更好的、支持混合类型的版本,它使用新的SimpleEntry<>(k, v)调用流。看看答案:https://stackoverflow.com/a/37384773/3950982