如何从String值中查找Java枚举?

How can I lookup a Java enum from its String value?

我想从枚举的字符串值(或者可能是任何其他值)中查找枚举。我已经尝试了以下代码,但它不允许在初始化器中使用静态代码。有简单的方法吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public enum Verbosity {

    BRIEF, NORMAL, FULL;

    private static Map<String, Verbosity> stringMap = new HashMap<String, Verbosity>();

    private Verbosity() {
        stringMap.put(this.toString(), this);
    }

    public static Verbosity getVerbosity(String key) {
        return stringMap.get(key);
    }
};


使用为每个枚举自动创建的valueOf方法。

1
Verbosity.valueOf("BRIEF") == Verbosity.BRIEF

对于任意值,从以下值开始:

1
2
3
4
5
6
7
8
public static Verbosity findByAbbr(String abbr){
    for(Verbosity v : values()){
        if( v.abbr().equals(abbr)){
            return v;
        }
    }
    return null;
}

只有在分析器告诉您以后才能继续映射实现。

我知道它在迭代所有的值,但是只有3个枚举值,它几乎不值得做任何其他的工作,事实上,除非你有很多值,否则我不会为一个映射而烦恼,它将足够快。


你离我很近。对于任意值,请尝试如下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public enum Day {

    MONDAY("M"), TUESDAY("T"), WEDNESDAY("W"),
    THURSDAY("R"), FRIDAY("F"), SATURDAY("Sa"), SUNDAY("Su"), ;

    private final String abbreviation;

    // Reverse-lookup map for getting a day from an abbreviation
    private static final Map<String, Day> lookup = new HashMap<String, Day>();

    static {
        for (Day d : Day.values()) {
            lookup.put(d.getAbbreviation(), d);
        }
    }

    private Day(String abbreviation) {
        this.abbreviation = abbreviation;
    }

    public String getAbbreviation() {
        return abbreviation;
    }

    public static Day get(String abbreviation) {
        return lookup.get(abbreviation);
    }
}


用Java 8可以用这种方式实现:

1
2
3
public static Verbosity findByAbbr(final String abbr){
    return Arrays.stream(values()).filter(value -> value.abbr().equals(abbr)).findFirst().orElse(null);
}


@Lyle的答案相当危险,我已经看到它不起作用,特别是如果您使枚举成为一个静态的内部类。相反,我使用了这样的方法,它将在枚举之前加载bootstrapsingleton映射。

编辑这应该不再是现代JVM(JVM 1.6或更高版本)的问题,但我认为JREBEL仍然存在问题,但我没有机会重新测试它。

先载我:

1
2
3
4
5
   public final class BootstrapSingleton {

        // Reverse-lookup map for getting a day from an abbreviation
        public static final Map<String, Day> lookup = new HashMap<String, Day>();
   }

现在将其加载到枚举构造函数中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
   public enum Day {
        MONDAY("M"), TUESDAY("T"), WEDNESDAY("W"),
        THURSDAY("R"), FRIDAY("F"), SATURDAY("Sa"), SUNDAY("Su"), ;

        private final String abbreviation;

        private Day(String abbreviation) {
            this.abbreviation = abbreviation;
            BootstrapSingleton.lookup.put(abbreviation, this);
        }

        public String getAbbreviation() {
            return abbreviation;
        }

        public static Day get(String abbreviation) {
            return lookup.get(abbreviation);
        }
    }

如果您有一个内部枚举,那么您只需定义枚举定义上方的映射,并且(理论上)应该在加载之前就完成了。


您不能使用valueof()?

编辑:顺便说一句,没有什么能阻止您在枚举中使用static。


在Java语言规范7中有一个例子!这反映了您关于用自引用初始化映射的问题。


如果它能帮助其他人,我喜欢的选项(这里没有列出)使用了番石榴的地图功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public enum Vebosity {
    BRIEF("BRIEF"),
    NORMAL("NORMAL"),
    FULL("FULL");

    private String value;
    private Verbosity(final String value) {
        this.value = value;
    }

    public String getValue() {
        return this.value;
    }

    private static ImmutableMap<String, Verbosity> reverseLookup =
            Maps.uniqueIndex(Arrays.asList(Verbosity.values()), Verbosity::getValue);

    public static Verbosity fromString(final String id) {
        return reverseLookup.getOrDefault(id, NORMAL);
    }
}

默认情况下,您可以使用nullthrow IllegalArgumentExceptionfromString返回Optional,无论您喜欢什么行为。


也许,看看这个。这对我很有效。这样做的目的是查找"红色"和"/red"颜色。如果enum多,只声明一次static map和加载一次enum将带来一些性能优势。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class Mapper {

public enum Maps {

    COLOR_RED("/red_color","RED");

    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 name();
    }

    public String getDescription() {
        return description;
    }

    public String getName() {
        return name();
    }

    public static String getColorName(String uri) {
        if (mMap == null) {
            initializeMapping();
        }
        if (mMap.containsKey(uri)) {
            return mMap.get(uri);
        }
        return null;
    }

    private static void initializeMapping() {
        mMap = new HashMap<String, String>();
        for (Maps s : Maps.values()) {
            mMap.put(s.code, s.description);
        }
    }
}
}

请把你的鸦片片放进去。


由于Java 8,您可以在单行中初始化映射,而无需静态块。

1
2
private static Map<String, Verbosity> stringMap = Arrays.stream(values())
                 .collect(Collectors.toMap(Enum::toString, Function.identity()));

可以将枚举定义为以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public enum Verbosity
{
   BRIEF, NORMAL, FULL, ACTION_NOT_VALID;
   private int value;

   public int getValue()
   {
     return this.value;
   }

   public static final Verbosity getVerbosityByValue(int value)
   {
     for(Verbosity verbosity : Verbosity.values())
     {
        if(verbosity.getValue() == value)
            return verbosity ;
     }

     return ACTION_NOT_VALID;
   }

   @Override
   public String toString()
   {
      return ((Integer)this.getValue()).toString();
   }
};

请参阅以下链接了解更多说明


您可以使用上面gareth davis&brad mace建议的Enum::valueOf()函数,但请确保处理如果使用的字符串不在枚举中时将抛出的IllegalArgumentException