从String转换为具有大量值的Java枚举

时间:2014-12-30 09:51:03

标签: java enums

假设我有一个包含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);
    }
}

5 个答案:

答案 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等),我建议使用它,因为它不需要额外的编码,因此是最容易理解的。