如何在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,使其更适合静态导入。
我强烈建议使用“双大括号初始化”风格而不是静态块风格。
有人可能会说他们不喜欢匿名类、开销、性能等。
但我更多考虑的是代码的可读性和可维护性。从这个角度来看,我认为双大括号是一种比静态方法更好的代码风格。
元素是嵌套的和内联的。
它更偏向于面向对象,而不是程序性的。
性能影响非常小,可以忽略不计。
更好的IDE大纲支持(而不是许多匿名的静态{}块)
你节省了几行评论来给他们带来关系。
从异常和字节码优化器防止未初始化对象的可能的元素泄漏/实例导致。
不用担心静态块的执行顺序。
此外,如果你知道匿名类的GC,你总是可以通过使用新的HashMap(Map Map)将其转换为普通的HashMap。
你可以这样做,直到你遇到另一个问题。如果你这样做,你应该使用完全另一种编码风格(例如,没有静态的,工厂类)。
我还没有在任何答案中看到我使用的方法(并且已经逐渐喜欢上了),所以这里是:
我不喜欢使用静态初始化器,因为它们很笨拙,
我不喜欢匿名类,因为它为每个实例创建一个新类。
相反,我更喜欢这样的初始化:
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对象初始化那样好,但就可读性而言,这是朝着那个方向迈出的一步。