假设我有一个包含100个值的枚举。为简单起见,请参考以下示例:
public enum code
{
CODE_1("string1"),
CODE_2("string2"),
CODE_3("string3"),
CODE_4("string4"),
...
}
我想创建一个公共方法,将具有已知格式的字符串(如“string1”,“string2”...)转换为适当的枚举值CODE_1,CODE_2 ...通常,这是通过迭代所有值来完成的,如果找到匹配项,则返回该枚举值。 (详情见in this question。)
但是,我关注reguraly循环遍历所有值。这可能是一个巨大的瓶颈吗?如果不是100个元素,那么会有1000个?
作为我自己的练习,我尝试使用静态地图优化此查找,这可以确保给定任何字符串的O(1)查找时间。我喜欢这个额外的噱头,但我只想在我的代码中包含它,如果它确实是必要的。您对使用迭代方法与地图方法有什么想法和发现?
public enum Code
{
...
//enum values
...
//The string-to-Code map
private static final Map<String,Code> CODE_MAP = populateMap();
private static Map<String,Code> populateMap()
{
Map<String,Code> map = new HashMap<String,Code>();
for(Code c : Code.values())
{
map.put(c.getCode(), c);
}
return map;
}
private String code;
private Code(String code)
{
this.code = code;
}
public String getCode()
{
return this.code;
}
public Code convertFromString(String code)
{
//assume that the given string is actually a key value in the map
return (Code) CODE_MAP.get(code);
}
}
答案 0 :(得分:40)
你想要一个Map<String, Code>
,但如何整齐地填充它?枚举不允许您在枚举实例初始化之前初始化静态字段,但是有一个简洁的小技巧,称为Initialization-on-demand holder idiom,这使得使用此功能所需的静态初始化地图变得容易实施:
public enum Code {
CODE_1("string1"),
CODE_2("string2"),
CODE_3("string3"),
// etc
;
private static class Holder {
static Map<String, Code> CODE_MAP = new HashMap<>();
}
private final String code;
private Code(String code) {
this.code = code;
Holder.CODE_MAP.put(code, this);
}
public String getCode() {
return this.code;
}
public Code convertFromString(String code) {
return CODE_MAP.get(code);
}
}
这是有效的,因为类加载器在初始化枚举类之前初始化内部静态类,因此在枚举实例初始化期间已准备好加载映射。
没有循环。没有特殊的代码来加载地图(在构造函数中完成)。最小的代码。
答案 1 :(得分:4)
地图是不错的选择:更干净的代码和O(1)
。如果您使用for-loop
,那么您获得的最好成绩是O(n)
答案 2 :(得分:4)
您提供的解决方案是正确实施的。
因为你必须只公开一种方法而且它更具可读性。
使用Map
代替iterating it manually
总是好的。
正如您所提到的那样,复杂性为O(1)
。
+1 to your question
,因为它提供a cleaner approach to use enum in some usecases
。
答案 3 :(得分:4)
如果您的字符串代码值是已知且一致的格式,则可以避免使用Map及其消耗的内存并动态构建CODE枚举查找值:
public static Code convertFromString(String code) {
return valueOf("CODE_" + code.substring("string".length()));
}
答案 4 :(得分:3)
嗯,map-solution的替代方案是一个巨大的switch语句(可以自动生成)或二进制搜索包含字符串的数组。我不认为要么大幅度地击败HashMap的表现,不过如果它真的很重要,你可能最好通过基准测试。
没有提到的一件事是,如果Enum.valueOf()具有其中一个枚举成员的确切名称,它将如何将String转换为枚举值。如果你的情况完全可能(仅仅看你的例子,我不知道Code.CODE_1怎么不能轻易地重命名为Code.string1等),我建议使用它,因为它不需要额外的编码,因此是最容易理解的。