如何在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...
}
}
我会用:
public class Test {
private static final Map<Integer, String> MY_MAP = createMap();
private static Map<Integer, String> createMap() {
Map<Integer, String> result = new HashMap<>();
result.put(1, "one");
result.put(2, "two");
return Collections.unmodifiableMap(result);
}
}
它避免了匿名类,我个人认为这是一种糟糕的风格,并避免
它使地图的创建更加明确
它使地图不可修改
因为MY_MAP是常量,所以我把它命名为常量
和往常一样,apache-commons有合适的方法MapUtils。putAll(地图、对象[]):
例如,要创建一个彩色地图:
Map<String, String> colorMap = MapUtils.putAll(new HashMap<String, String>(), new String[][] {
{"RED", "#FF0000"},
{"GREEN", "#00FF00"},
{"BLUE", "#0000FF"}
});
在这种情况下,我绝不会创建匿名子类。静态初始化器同样有效,如果你想让映射不可修改,例如:
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);
}
我喜欢使用静态初始化“技术”,当我有一个抽象类的具体实现,它定义了一个初始化构造函数,但没有默认构造函数,但我希望我的子类有一个默认构造函数。
例如:
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...
}
}
我已经读了答案,我决定写我自己的地图生成器。请随意复制粘贴并欣赏。
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,使其更适合静态导入。