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

当前回答

现在Java 8已经发布了,这个问题值得重新审视。我尝试了一下——看起来也许你可以利用lambda表达式语法来获得一个非常漂亮和简洁(但类型安全)的映射文字语法,看起来像这样:

Map<String,Object> myMap = hashMap(
    bob -> 5,
    TheGimp -> 8,
    incredibleKoolAid -> "James Taylor",
    heyArnold -> new Date()
);

Map<String,Integer> typesafeMap = treeMap(
    a -> 5,
    bee -> 8,
    sea -> 13
    deep -> 21
);

未经测试的示例代码在https://gist.github.com/galdosd/10823529 会对其他人对此的看法感到好奇(这有点邪恶…)

其他回答

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

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

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

如果你想要一些简洁和相对安全的东西,你可以将编译时类型检查转移到运行时:

static final Map<String, Integer> map = MapUtils.unmodifiableMap(
    String.class, Integer.class,
    "cat",  4,
    "dog",  2,
    "frog", 17
);

这个实现应该捕获任何错误:

import java.util.HashMap;

public abstract class MapUtils
{
    private MapUtils() { }

    public static <K, V> HashMap<K, V> unmodifiableMap(
            Class<? extends K> keyClazz,
            Class<? extends V> valClazz,
            Object...keyValues)
    {
        return Collections.<K, V>unmodifiableMap(makeMap(
            keyClazz,
            valClazz,
            keyValues));
    }

    public static <K, V> HashMap<K, V> makeMap(
            Class<? extends K> keyClazz,
            Class<? extends V> valClazz,
            Object...keyValues)
    {
        if (keyValues.length % 2 != 0)
        {
            throw new IllegalArgumentException(
                    "'keyValues' was formatted incorrectly!  "
                  + "(Expected an even length, but found '" + keyValues.length + "')");
        }

        HashMap<K, V> result = new HashMap<K, V>(keyValues.length / 2);

        for (int i = 0; i < keyValues.length;)
        {
            K key = cast(keyClazz, keyValues[i], i);
            ++i;
            V val = cast(valClazz, keyValues[i], i);
            ++i;
            result.put(key, val);
        }

        return result;
    }

    private static <T> T cast(Class<? extends T> clazz, Object object, int i)
    {
        try
        {
            return clazz.cast(object);
        }
        catch (ClassCastException e)
        {
            String objectName = (i % 2 == 0) ? "Key" : "Value";
            String format = "%s at index %d ('%s') wasn't assignable to type '%s'";
            throw new IllegalArgumentException(String.format(format, objectName, i, object.toString(), clazz.getSimpleName()), e);
        }
    }
}

我做了一些不同的事情。不是最好的,但对我有用。也许它可以被“泛化”。

private static final Object[][] ENTRIES =
{
  {new Integer(1), "one"},
  {new Integer(2), "two"},
};
private static final Map myMap = newMap(ENTRIES);

private static Map newMap(Object[][] entries)
{
  Map map = new HashMap();

  for (int x = 0; x < entries.length; x++)
  {
    Object[] entry = entries[x];

    map.put(entry[0], entry[1]);
  }

  return map;
}

我强烈建议使用“双大括号初始化”风格而不是静态块风格。

有人可能会说他们不喜欢匿名类、开销、性能等。

但我更多考虑的是代码的可读性和可维护性。从这个角度来看,我认为双大括号是一种比静态方法更好的代码风格。

元素是嵌套的和内联的。 它更偏向于面向对象,而不是程序性的。 性能影响非常小,可以忽略不计。 更好的IDE大纲支持(而不是许多匿名的静态{}块) 你节省了几行评论来给他们带来关系。 从异常和字节码优化器防止未初始化对象的可能的元素泄漏/实例导致。 不用担心静态块的执行顺序。

此外,如果你知道匿名类的GC,你总是可以通过使用新的HashMap(Map Map)将其转换为普通的HashMap。

你可以这样做,直到你遇到另一个问题。如果你这样做,你应该使用完全另一种编码风格(例如,没有静态的,工厂类)。