public enum Maps {
COLOR_RED("ABC", "abc description");
private final String code;
private final String description;
private static Map<String, String> mMap;
private Maps(String code, String description) {
this.code = code;
this.description = description;
}
public String getCode() {
return code;
}
public String getDescription() {
return description;
}
public static String getDescriptionByCode(String code) {
if (mMap == null) {
initializeMapping();
}
if (mMap.containsKey(code)) {
return mMap.get(code);
}
return null;
}
private static void initializeMapping() {
mMap = new HashMap<String, String>();
for (Maps s : Maps.values()) {
mMap.put(s.code, s.description);
}
}
}
#1 楼
您的代码非常整洁,只有一件事我需要更改:private static Map<String, String> mMap;
到
private static final Map<String, String> mMap = Collections.unmodifiableMap(initializeMapping());
原因:
通过不声明final并且不使用对
unmodifiableMap
的调用是可变的,因此可以使用反射修改引用或在.remove("ABC")
上使用地图。将其声明为final可以确保引用的映射不能更改,而unmodifiableMap可以确保对映射本身无法进行任何更改。多线程问题。按照目前的情况,如果两个线程同时调用
getDescriptionByCode
方法,则将初始化两次映射,这是不需要的。当然,这也需要对
initializeMapping()
稍作更改:private static Map<String, String> initializeMapping() {
Map<String, String> mMap = new HashMap<String, String>();
for (Maps s : Maps.values()) {
mMap.put(s.code, s.description);
}
return mMap;
}
除此之外,一切看起来都不错。干得好!
#2 楼
您可以将以下内容更改为:if (mMap.containsKey(code)) {
return mMap.get(code);
}
return null;
到:
return mMap.get(code);
HashMap.get()
如果地图中没有这样的键,则返回null
。评论
\ $ \ begingroup \ $
实际上,您应该这样做。它更短并且更好地利用了api。您可以添加注释(对于不熟悉Map api的ppl),以告知是否不包含键,则返回null
\ $ \ endgroup \ $
–RobAu
2014年4月4日15:31
#3 楼
这可能只是一个偏好问题,但对我来说,让地图存储Maps
的实例而不是直接存储描述似乎更有用,因为那样您还可以免费获得其他信息的功能(枚举项名称,其序数值等)。您可能不需要此功能,但是因为它非常简单,所以我肯定会认为更好。#4 楼
对于此类,相对于它添加的复杂性,延迟初始化带来的好处太少。枚举中只有一个成员,并且枚举的每个成员构造起来都很简单。因此,您应该在类加载时使用静态初始化程序块填充映射。 (此外,它保证初始化仅发生一次,因此是线程安全的。)public enum Maps {
COLOR_RED("ABC", "abc description");
private final String code;
private final String description;
private static final Map<String, String> MAP = new HashMap<String, String>();
static {
for (Maps s : Maps.values()) {
MAP.put(s.code, s.description);
}
}
private Maps(String code, String description) {
this.code = code;
this.description = description;
}
public String getCode() {
return code;
}
public String getDescription() {
return description;
}
public static String getDescriptionByCode(String code) {
return MAP.get(code);
}
}
此外,如果
COLOR_RED
没有任何有用的含义,并且代码字符串也是有效的Java标识符,请考虑将代码本身用作每个枚举成员的名称。枚举已经具有按名称查找成员的功能,因此您可以利用该机制。public enum SimplerMap {
ABC("abc description");
private final String description;
private SimplerMap(String description) {
this.description = description;
}
public String getCode() {
return this.toString();
}
public String getDescription() {
return this.description;
}
public static String getDescriptionByCode(String code) {
try {
return valueOf(code).getCode();
} catch (IllegalArgumentException noSuchCode) {
return null;
}
}
}
#5 楼
首先,代码中的名称不是很清楚。Maps
是什么意思?为什么使用COLOR_RED
以及为什么关联的代码ABC
?枚举中只有一个值吗?
也许这只是示例代码,但这很难分析。
例如,如果您的值名为
ABC
,则只需调用Maps.valueOf("ABC")
即可拥有关联的枚举并获取相应的描述,而无需内部映射。当然,如果您需要
Colors
和Codes
,都必须以某种方式将它们关联。但是,为什么还要使用字符串呢?也许您可以使用另一个称为Colors
的枚举(定义COLOR_RED),以便仅使用枚举类型来完成颜色和代码之间的关系。 我已经有一段时间没有用Java编写了,但是如果我没记错的话,
EnumMap
s(例如,从Colors
到Codes
以及相反)非常有效(就像数组中的整数索引一样);而且,枚举的switch
案例效率也更高,并提供了来自编译器的更多反馈:静态分析可以告诉您是否考虑了所有可能的枚举;这大大简化了您的代码,因为您无需费心进行错误检查。当然,处理来自应用程序外部的数据时,字符串是必需的。但是在内部交换数据时,大多数情况下可以避免这种情况。
希望这会有所帮助。
#6 楼
只需在静态块中初始化不可变映射即可。此外,放置lambda可以达到更高的目标:
private static final Map<String, String> mapCodes = new HashMap<>();
static {
final Map<String, String> items = EnumSet.allOf(Maps.class)
.stream()
/*.filter(// Can do some filtering excluding values) */
.collect(Collectors.toMap(Maps::code, Maps::description));
mapCodes.putAll(items);
}
根据可重用性的级别,建议访问唯一值和Enum实例。 br />
.collect(Collectors.toMap(Maps::code, m-> m));
另外,在吸气方法中可以增强不变性,如:
番石榴:
ImmutableMap.copyOf(mapCodes) //Recommended: Protects original map values of being mutated
:
Java集合:
Collections.unmodifiableMap(mapCodes)
评论
\ $ \ begingroup \ $
要解决这些多线程问题,请使用静态初始化块,该块必须运行一次。
\ $ \ endgroup \ $
– wchargin
14年4月4日在16:33
\ $ \ begingroup \ $
@WChargin AFAIK私有静态最终Map
\ $ \ endgroup \ $
–西蒙·福斯伯格
14年4月4日在16:38
\ $ \ begingroup \ $
WTF? mMap是私有的;没有什么可以更改它引用的对象或从地图添加/删除条目的。是的,您可以使用反射,但是在几乎所有情况下,尝试设计类以防止反射将其内部结构弄乱都是一个糟糕的主意。
\ $ \ endgroup \ $
–布赖恩·戈登(Brian Gordon)
15年2月18日在22:22
\ $ \ begingroup \ $
@BrianGordon使其私有且不可修改,可以防止您将来意外编写修改该代码的代码。另外,在检查代码时,可以很容易地看到代码的预期用途。我在这里不是在谈论反思。
\ $ \ endgroup \ $
–西蒙·福斯伯格
2015年2月18日在23:26