如何从Java中的字符串值获取枚举值?


1982

说我有一个枚举

public enum Blah {
    A, B, C, D
}

我想找到一个字符串的枚举值,例如"A"这将是Blah.A。怎么可能做到这一点?

Enum.valueOf()我需要的方法吗?如果是这样,我将如何使用它?

Answers:


2258

是的,Blah.valueOf("A")会给你的Blah.A

请注意,该名称必须是精确匹配,包括大小写:Blah.valueOf("a")Blah.valueOf("A ")两抛出IllegalArgumentException

静态方法valueOf()values()是在编译时创建的,不会出现在源代码中。但是,它们确实出现在Javadoc中。例如,Dialog.ModalityType显示两种方法。


100
作为参考,该Blah.valueOf("A")方法区分大小写,并且不容许多余的空格,因此@JoséMi在下面提出了替代解决方案。
Brett 2013年

3
@Michael Myers,由于此答案是迄今为止票数最高的,我是否应该理解将枚举及其String值定义为完全相同是一种好习惯?
凯文·梅雷迪斯

4
@KevinMeredith:如果您的意思是toString()值,不,我不会那么说。name()除非覆盖它,否则它将为您提供枚举常量的实际定义名称。
迈克尔·迈尔斯

3
您的确切含义是“在编译时创建的,而不出现在源代码中”。?
treesAreEverywhere

8
@treesAreEverywhere更具体地说,这些方法由编译器生成(或合成)。实际的enum Blah {...}定义不应尝试声明其自己的valuesnor valuesOf。就像您从未真正声明“ class”成员变量时,您就可以编写“ AnyTypeName.class”一样。编译器使一切正常。(此答案可能在3个月后不再对您有用,但以防万一。)
Ti Strga 2014年

864

如果文本与枚举值不同,则另一种解决方案:

public enum Blah {
    A("text1"),
    B("text2"),
    C("text3"),
    D("text4");

    private String text;

    Blah(String text) {
        this.text = text;
    }

    public String getText() {
        return this.text;
    }

    public static Blah fromString(String text) {
        for (Blah b : Blah.values()) {
            if (b.text.equalsIgnoreCase(text)) {
                return b;
            }
        }
        return null;
    }
}

396
throw new IllegalArgumentException("No constant with text " + text + " found")会比return null
whiskeysierra

8
@whiskeysierra乔恩·斯基特(Jon Skeet)对此表示不同意。stackoverflow.com/questions/1167982/...
Sanghyun李

11
@Sangdol 能启发我们为什么返回null更好吗?
whiskeysierra

57
@Sangdol通常,检查SUN-哎呀-Oracle在相同情况下正在执行的操作是一件好事。而作为Enum.valueOf()正显示出它IS抛出一个异常在这种情况下,最好的做法。因为这是例外情况。“性能优化”是编写不可读代码的不好借口;-)
raudi

5
嗯,你也可以利用@Nullable注释,使其“可读” ;-)
何塞米

121

这是我使用的一个漂亮的实用程序:

/**
 * A common method for all enums since they can't have another base class
 * @param <T> Enum type
 * @param c enum type. All enums must be all caps.
 * @param string case insensitive
 * @return corresponding enum, or null
 */
public static <T extends Enum<T>> T getEnumFromString(Class<T> c, String string) {
    if( c != null && string != null ) {
        try {
            return Enum.valueOf(c, string.trim().toUpperCase());
        } catch(IllegalArgumentException ex) {
        }
    }
    return null;
}

然后在我的枚举类中,我通常用它来保存一些输入内容:

public static MyEnum fromString(String name) {
    return getEnumFromString(MyEnum.class, name);
}

如果您的枚举不是全部大写,则只需更改Enum.valueOf行即可。

太糟糕了,我无法使用T.classEnum.valueOf因为T已删除。


176
抱歉,那块空的渔获物确实使我发疯。
whiskeysierra

32
@LazloBonin:例外是针对特殊情况,而不是控制流。获得有效Java的副本。
恢复莫妮卡

10
如果要使用的Java API引发异常,并且您不希望代码引发异常,则可以像这样吞下该异常,或者从头开始重写逻辑,这样一开始就不会引发异常。吞下例外通常是较小的邪恶。
Nate CK

47
可怕!一直以来,始终捕获异常,您可以处理它们。上面的示例是一个完美的示例,说明如何不这样做。为什么?因此它返回NULL,然后调用者必须检查NULL或抛出NPE。如果调用者知道如何处理这种情况,则执行if vs. try-catch可能看起来更优雅,但是如果他不能处理,则必须再次传递null,并且调用者的调用者必须再次检查NULL ,等等。等等
raudi 2012年

10
为了与上述解决方案公平起见,确实存在用例,要求您返回null而不是抛出IllegalArgumentException并破坏程序流,例如,在Web服务架构和数据库架构之间映射枚举,但它们并不总是一个一对一。但是,我同意不要将catch块留空。输入诸如log.warn之类的代码或用于跟踪目的的代码。
阿德里安M

101

使用有效Java的 Joshua Bloch提供的模式:

(为简化起见)

enum MyEnum {
    ENUM_1("A"),
    ENUM_2("B");

    private String name;

    private static final Map<String,MyEnum> ENUM_MAP;

    MyEnum (String name) {
        this.name = name;
    }

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

    // Build an immutable map of String name to enum pairs.
    // Any Map impl can be used.

    static {
        Map<String,MyEnum> map = new ConcurrentHashMap<String, MyEnum>();
        for (MyEnum instance : MyEnum.values()) {
            map.put(instance.getName(),instance);
        }
        ENUM_MAP = Collections.unmodifiableMap(map);
    }

    public static MyEnum get (String name) {
        return ENUM_MAP.get(name);
    }
}

另请参阅:

使用实例枚举和映射的Oracle Java示例

Enum类型的静态块的执行顺序

如何从其String值查找Java枚举


4
如果约书亚·布洛赫(Joshua Bloch)这么说,那么这是唯一的选择。我总是不得不在这里向下滚动,真是太可惜了。
dermoritz

11
在Java 8中,这甚至更简单:Stream.of(MyEnum.values()).collect(toMap(Enum::name, identity()))我还建议重写toString()(通过构造函数传递),并使用它代替名称,尤其是如果Enum与可序列化数据相关联,因为这使您可以控制外壳而无需给出声纳适合。
Novaterata

1
Java 8当然可以/将在这个论坛上改变很多(更好)的答案。虽然不确定是否有尾巴(声纳)会w狗(应用程序代码)。
Darrell Teague

3
如果仍然要放进去unmodifiableMap,那么从开始就没有好处ConcurrentHashMap。只需使用一个HashMap。(如果您有番石榴,ImmutableMap那么我建议您代替!)
Daniel Pryden

9
静态初始化本质上是同步的,因此这里绝对没有理由使用ConcurrentHashMap,因为在初始化之后永远不会修改映射。因此,为什么甚至在JLS中的示例本身也使用常规HashMap
Radiodef

74

您还应该谨慎对待自己的情况。让我解释一下:做事Blah.valueOf("A"),但是Blah.valueOf("a")行不通。然后Blah.valueOf("a".toUpperCase(Locale.ENGLISH))又会工作。

编辑
更改toUpperCasetoUpperCase(Locale.ENGLISH)基于tc。注释Java文档

sulai指出Locale.US, 在android上,您应该使用edit2


6
注意默认语言环境!
tc。

3
对于您在那里的Android用户,我想指出,Android文档明确鼓励使用Locale.US机器可读输入/输出。
sulai

2
@Trengot是的,很不幸。土耳其就是一个很好的例子。将此与Java对默认字符集的不正确处理(Windows上默认为Latin而不是Unicode)结合使用时,您会发现使用默认版本的接受字符集或语言环境的方法几乎总是不安全的。您几乎应该始终明确定义它们。
Stijn de Witt

不确定Java的“默认”字符集等本身是否被“破坏”,但是否被授予,默认使用UTF-8代替替代(应始终明确表示)会为通常无法理解的初级程序员提供更好的系统字符集的概念。
达雷尔·蒂格

38

这是一种可以对任何枚举执行此操作的方法,并且不区分大小写。

/** 
 * Finds the value of the given enumeration by name, case-insensitive. 
 * Throws an IllegalArgumentException if no match is found.  
 **/
public static <T extends Enum<T>> T valueOfIgnoreCase(
        Class<T> enumeration, String name) {

    for (T enumValue : enumeration.getEnumConstants()) {
        if (enumValue.name().equalsIgnoreCase(name)) {
            return enumValue;
        }
    }

    throw new IllegalArgumentException(String.format(
        "There is no value with name '%s' in Enum %s",
        name, enumeration.getName()
    ));
}

这种变化正确地做到了:这equalsIgnoreCase是要走的路。+1
斯蒂恩·德·威特

像不区分大小写一样,但是...(随机数)更喜欢枚举(Enums)作为键的字符串分配,... ...较小,但是对于这种可能重复的查找而言,迭代的性能较差。因此,EnumMap等的实现。
Darrell Teague

这行不通!我出于自己的目的将equalsIgnoreCase更改为equals。即使两个相等的输入都完全相同,代码也会失败。
MasterJoe2

36

使用Blah.valueOf(string)是最好的,但您也可以使用Enum.valueOf(Blah.class, string)


1
区分大小写,无济于事!
Murtaza Kanchwala

@MurtazaKanchwala您可以澄清您的评论吗?你想做什么?
彼得·劳里

2
@PeterLawrey,您好,我正试图从String公共枚举ObjectType {PERSON(“ Person”)public String parameterName;中获取一个枚举。ObjectType(String parameterName){this.parameterName = parameterName; } public String getParameterName(){返回this.parameterName; } public static ObjectType fromString(String parameterName){if(parameterName!= null){for(ObjectType objType:ObjectType.values()){if(parameterName.equalsIgnoreCase(objType.parameterName)){return objType; 返回空值;}
Murtaza Kanchwala 2015年

34

在Java 8或更高版本中,使用Streams

public enum Blah
{
    A("text1"),
    B("text2"),
    C("text3"),
    D("text4");

    private String text;

    Blah(String text) {
        this.text = text;
    }

    public String getText() {
        return this.text;
    }

    public static Optional<Blah> fromText(String text) {
        return Arrays.stream(values())
          .filter(bl -> bl.text.equalsIgnoreCase(text))
          .findFirst();
    }
}

不确定这是否是更好的答案。在这种情况下,流是一个单线程迭代器,它在所有值上都像其他任何迭代器一样,并且性能可能比映射查找impl低。在多线程上下文中,流具有更大的价值,例如,并行执行换行符分隔的文本文件可以提高性能。
Darrell Teague

28

如果您不想编写自己的实用程序,请使用Google的 图书馆:

Enums.getIfPresent(Blah.class, "A")

与内置的Java函数不同,它让您检查Bl中是否存在A且不引发异常。


7
可悲的是,这将返回google可选而不是java可选
javaProgrammer

真正。虽然被淘汰。Google和Netflix具有强大的Java库。在较新版本中实现的Java追赶类存在重叠之处,不可避免地会引起麻烦。某种必须全部集中在一个供应商库中。
Darrell Teague

26

我在这里的2美分:使用Java8流+检查确切的字符串:

public enum MyEnum {
    VALUE_1("Super"),
    VALUE_2("Rainbow"),
    VALUE_3("Dash"),
    VALUE_3("Rocks");

    private final String value;

    MyEnum(String value) {
        this.value = value;
    }

    /**
     * @return the Enum representation for the given string.
     * @throws IllegalArgumentException if unknown string.
     */
    public static MyEnum fromString(String s) throws IllegalArgumentException {
        return Arrays.stream(MyEnum.values())
                .filter(v -> v.value.equals(s))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("unknown value: " + s));
    }
}

**编辑**

将函数重命名为fromString()自使用该约定命名以来,您将从Java语言本身中获得了一些好处;例如:

  1. 直接在HeaderParam批注中转换类型

1
或者,为了允许您编写更多可读的switch块,可以使用.orElse(null)代替,.orElseThrow()以便可以对子default句中的异常引发进行编码-并在需要时提供更多有用的信息。为了使它更宽大,您可以使用v -> Objects.equals(v.name, s == null ? "" : s.trim().toUpperCase())
亚当(Adam)

或者只返回OptionalfindFirst(),允许用户如果他要决定.orElse(null)orElseThrow()或任何....
user85421

1
声明a public static MyEnum valueOf(String)实际上是一个编译错误,因为它与隐式定义的错误相同,因此答案的旧版本实际上更好。(jlsideone
Radiodef

在我的选择中,最好避免Exception并使用Optional。紧接着,我们应该使null无效,并改用Optional。
汉斯·施罗德

再次提醒您,即使代码看起来更少或更好...像这样的Stream实现也只是所有值与映射查找(性能较差)的迭代器。
Darrell Teague

16

您可能需要这样做:

public enum ObjectType {
    PERSON("Person");

    public String parameterName;

    ObjectType(String parameterName) {
        this.parameterName = parameterName;
    }

    public String getParameterName() {
        return this.parameterName;
    }

    //From String method will return you the Enum for the provided input string
    public static ObjectType fromString(String parameterName) {
        if (parameterName != null) {
            for (ObjectType objType : ObjectType.values()) {
                if (parameterName.equalsIgnoreCase(objType.parameterName)) {
                    return objType;
                }
            }
        }
        return null;
    }
}

再增加一个:

   public static String fromEnumName(String parameterName) {
        if (parameterName != null) {
            for (DQJ objType : DQJ.values()) {
                if (parameterName.equalsIgnoreCase(objType.name())) {
                    return objType.parameterName;
                }
            }
        }
        return null;
    }

这将通过字符串化的枚举名称返回值。例如,如果在fromEnumName中提供“ PERSON”,它将返回枚举值,即“ Person”


13

通过使用name()Enum的隐式静态方法来执行此操作的另一种方法。name将返回用于创建该枚举的确切字符串,该字符串可用于对照提供的字符串进行检查:

public enum Blah {

    A, B, C, D;

    public static Blah getEnum(String s){
        if(A.name().equals(s)){
            return A;
        }else if(B.name().equals(s)){
            return B;
        }else if(C.name().equals(s)){
            return C;
        }else if (D.name().equals(s)){
            return D;
        }
        throw new IllegalArgumentException("No Enum specified for this string");
    }
}

测试:

System.out.println(Blah.getEnum("B").name());

//it will print B  B

灵感:Java中Enum的10个示例


7
这本质上就是valueOf为您服务。这种静态方法没有提供任何额外的东西,例外等等。然后,if / else构造非常危险……添加任何新的枚举常量都将导致此方法不做任何更改就被破坏。
YoYo 2012年

请考虑以下示例,说明如何使用valueOf进行不区分大小写的查找,或者如何避免使用它的异常并使用别名来提供备用名称:stackoverflow.com/a/12659023/744133
YoYo 2012年

2
name()不是静态的。
nrubin29

10

使用Guava库的解决方案。方法getPlanet()不区分大小写,因此getPlanet(“ MerCUrY”)将返回Planet.MERCURY。

package com.universe.solarsystem.planets;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Enums;
import com.google.common.base.Optional;

//Pluto and Eris are dwarf planets, who cares!
public enum Planet {
   MERCURY,
   VENUS,
   EARTH,
   MARS,
   JUPITER,
   SATURN,
   URANUS,
   NEPTUNE;

   public static Planet getPlanet(String name) {
      String val = StringUtils.trimToEmpty(name).toUpperCase();
      Optional <Planet> possible = Enums.getIfPresent(Planet.class, val);
      if (!possible.isPresent()) {
         throw new IllegalArgumentException(val + "? There is no such planet!");
      }
      return possible.get();
   }
}

8

为了增加以前的答案,并解决有关null和NPE的一些讨论,我使用Guava Optionals处理缺席/无效案件。这非常适合URI /参数解析。

public enum E {
    A,B,C;
    public static Optional<E> fromString(String s) {
        try {
            return Optional.of(E.valueOf(s.toUpperCase()));
        } catch (IllegalArgumentException|NullPointerException e) {
            return Optional.absent();
        }
    }
}

对于那些不知道的人,这里有一些有关使用可选的避免空值的更多信息:https : //code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional


对于相关的模式以及在Enum中使用Optional的问题,这确实是一个很好的答案-利用Enum也是类的事实,因此可以用方法,重写方法等进行修饰。这对于Fluent风格的编程也是一个好案例从方法返回的null构成构造错误(NPE在方法调用的Fluent链中的未知位置)。
Darrell Teague

8

在Java 8中,静态Map模式更加简单,这是我的首选方法。如果要与Jackson一起使用Enum,则可以覆盖toString并使用它代替名称,然后使用注释@JsonValue

public enum MyEnum {
    BAR,
    BAZ;
    private static final Map<String, MyEnum> MAP = Stream.of(MyEnum.values()).collect(Collectors.toMap(Enum::name, Function.identity()));
    public static MyEnum fromName(String name){
        return MAP.get(name);
    }
}

public enum MyEnumForJson {
    BAR("bar"),
    BAZ("baz");
    private static final Map<String, MyEnumForJson> MAP = Stream.of(MyEnumForJson.values()).collect(Collectors.toMap(Object::toString, Function.identity()));
    private final String value;

    MyEnumForJson(String value) {
        this.value = value;
    }

    @JsonValue
    @Override
    public String toString() {
        return value;
    }

    public static MyEnumForJson fromValue(String value){
        return MAP.get(value);
    }
}

Jackson是JSON(JavaScript对象表示法)实现。最初的问题与JSON无关。
Darrell Teague

JSON部分只是我当时发现的相关内容,因为从字符串中获取Enum基本上是一种反序列化,而JSON / Jackson可能是最受欢迎的序列化解决方案。
Novaterata

理解但从适度的角度来看-它并没有帮助回答OP的问题,因此只是尝试在其中设置上下文。JSON确实是将对象转换为Java中规范形式的方法,而Jackson是一个很好的库。
Darrell Teague

6
public static MyEnum getFromValue(String value) {
    MyEnum resp = null;
    MyEnum nodes[] = values();
    for(int i = 0; i < nodes.length; i++) {
        if(nodes[i].value.equals(value)) {
            resp = nodes[i];
            break;
        }
    }
    return resp;
}

请查看此链接,以获取有关在stackoverflow.com上回答问题的指南: stackoverflow.com/faq
bakoyaro 2011年

1
这与JoséMi的答案大致相同
Rup

6

O(1)方法的灵感来自使用散列图的节俭生成的代码。

public enum USER {
        STUDENT("jon",0),TEACHER("tom",1);

        private static final Map<String, Integer> map = new HashMap<>();

        static {
                for (USER user : EnumSet.allOf(USER.class)) {
                        map.put(user.getTypeName(), user.getIndex());
                }
        }

        public static int findIndexByTypeName(String typeName) {
                return map.get(typeName);
        }

        private USER(String typeName,int index){
                this.typeName = typeName;
                this.index = index;
        }
        private String typeName;
        private int index;
        public String getTypeName() {
                return typeName;
        }
        public void setTypeName(String typeName) {
                this.typeName = typeName;
        }
        public int getIndex() {
                return index;
        }
        public void setIndex(int index) {
                this.index = index;
        }

}

请注意,零(0)和一(1)标识符是不必要的。枚举values()方法将以与编码相同的顺序返回成员。因此,第一项将是零序,第二个等
达雷尔蒂格

6

枚举非常有用,我一直在使用Enum很多语言为某些字段添加描述,例如以下示例:

public enum Status {

    ACT(new String[] { "Accepted", "مقبول" }),
    REJ(new String[] { "Rejected", "مرفوض" }),
    PND(new String[] { "Pending", "في الانتظار" }),
    ERR(new String[] { "Error", "خطأ" }),
    SNT(new String[] { "Sent", "أرسلت" });

    private String[] status;

    public String getDescription(String lang) {
        return lang.equals("en") ? status[0] : status[1];
    }

    Status(String[] status) {
        this.status = status;
    }
}

然后,您可以根据传递给getDescription(String lang)方法的语言代码来动态检索描述,例如:

String statusDescription = Status.valueOf("ACT").getDescription("en");

1
进一步推动枚举的典范。本来可以使用标准的静态名称和Map中的查询进行语言编码,但是仍然是一个很好的示例,该枚举具有本质上相同的逻辑值的带有不同标签的枚举。
Darrell Teague

5

关于什么?

public enum MyEnum {
    FIRST,
    SECOND,
    THIRD;

    public static Optional<MyEnum> fromString(String value){
        try{
            return Optional.of(MyEnum.valueOf(value));
        }catch(Exception e){
            return Optional.empty();
        }
    }
}

4

java.lang.Enum 定义了几种有用的方法,这些方法可用于Java中的所有枚举类型:

  • 您可以使用name()method获取任何Enum常量的名称。用于写枚举常量的字符串文字是它们的名称。
  • 类似地,values()方法可用于从Enum类型获取所有Enum常量的数组。
  • 对于询问的问题,您可以使用valueOf()方法将Java中的任何String转换为Enum常量,如下所示。
public class EnumDemo06 {
    public static void main(String args[]) {
        Gender fromString = Gender.valueOf("MALE");
        System.out.println("Gender.MALE.name() : " + fromString.name());
    }

    private enum Gender {
        MALE, FEMALE;
    }
}

Output:
Gender.MALE.name() : MALE

在此代码段中,valueOf()方法返回一个Enum常量Gender.MALE,并在上调用name "MALE"


4

Apache的commons-lang库具有一个静态函数org.apache.commons.lang3.EnumUtils.getEnum,它将一个String映射到您的Enum类型。答案基本上与Geoffreys相同,但是为什么当它已经在野外出现时为什么要自己动手。


1
合理的评论(DRY),但是...虽然大多数Apache Commons东西很棒,但是我在该基础上发现了一些错误和反模式。因此,提到约书亚·布洛赫(Joshua Bloch)的实施可能会立足。然后必须回顾Apache代码以了解某人实现了什么。如果说著名的道格·利亚(Doug Leah)重新编写了Java并发性,那么我将暗含信任它。
Darrell Teague

4

加上评分最高的答案,并提供有用的实用程序...

valueOf() 在不喜欢其输入的情况下抛出两个不同的异常。

  • IllegalArgumentException
  • NullPointerExeption

如果您的要求不能保证您的String一定与某个枚举值匹配,例如,如果String数据来自数据库并且可能包含旧版本的枚举,则您需要处理这些经常...

因此,这是我编写的可重用方法,该方法允许我们定义默认的Enum(如果我们传递的String不匹配,则返回该Enum)。

private static <T extends Enum<T>> T valueOf( String name , T defaultVal) {
        try {
            return Enum.valueOf(defaultVal.getDeclaringClass() , name);
        } catch (IllegalArgumentException | NullPointerException e) {
            return defaultVal;
        }
    }

像这样使用它:

public enum MYTHINGS {
    THINGONE,
    THINGTWO
}

public static void main(String [] asd) {
  valueOf("THINGTWO" , MYTHINGS.THINGONE);//returns MYTHINGS.THINGTWO
  valueOf("THINGZERO" , MYTHINGS.THINGONE);//returns MYTHINGS.THINGONE
}

2

由于switch尚未提及-version,因此我对其进行了介绍(重用OP的枚举):

  private enum Blah {
    A, B, C, D;

    public static Blah byName(String name) {
      switch (name) {
        case "A":
          return A;
        case "B":
          return B;
        case "C":
          return C;
        case "D":
          return D;
        default:
          throw new IllegalArgumentException(
            "No enum constant " + Blah.class.getCanonicalName() + "." + name);
      }
    }
  }

由于这不会给valueOf(String name)方法带来任何额外的价值,因此只有在我们想要具有不同的行为时才定义一个额外的方法才有意义。如果我们不想提高,IllegalArgumentException可以将实现更改为:

  private enum Blah {
    A, B, C, D;

    public static Blah valueOfOrDefault(String name, Blah defaultValue) {
      switch (name) {
        case "A":
          return A;
        case "B":
          return B;
        case "C":
          return C;
        case "D":
          return D;
        default:
          if (defaultValue == null) {
            throw new NullPointerException();
          }
          return defaultValue;
      }
    }
  }

通过提供默认值,我们可以保留的合同Enum.valueOf(String name)而不会抛出IllegalArgumentException 在任何情况下null都不会返回的方式。因此,NullPointerException如果名称为is null,则抛出if ,default如果if defaultValue则为null。就是这样valueOfOrDefault

这种方法采用了Map-Interface 的设计,该接口提供了Map.getOrDefault(Object key, V defaultValue)Java 8中的方法。


1

另一个以相反方式捕获的实用程序。使用标识该Enum的值,而不是根据其名称。

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.EnumSet;

public class EnumUtil {

    /**
     * Returns the <code>Enum</code> of type <code>enumType</code> whose a 
     * public method return value of this Enum is 
     * equal to <code>valor</code>.<br/>
     * Such method should be unique public, not final and static method 
     * declared in Enum.
     * In case of more than one method in match those conditions
     * its first one will be chosen.
     * 
     * @param enumType
     * @param value
     * @return 
     */
    public static <E extends Enum<E>> E from(Class<E> enumType, Object value) {
        String methodName = getMethodIdentifier(enumType);
        return from(enumType, value, methodName);
    }

    /**
     * Returns the <code>Enum</code> of type <code>enumType</code> whose  
     * public method <code>methodName</code> return is 
     * equal to <code>value</code>.<br/>
     *
     * @param enumType
     * @param value
     * @param methodName
     * @return
     */
    public static <E extends Enum<E>> E from(Class<E> enumType, Object value, String methodName) {
        EnumSet<E> enumSet = EnumSet.allOf(enumType);
        for (E en : enumSet) {
            try {
                String invoke = enumType.getMethod(methodName).invoke(en).toString();
                if (invoke.equals(value.toString())) {
                    return en;
                }
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

    private static String getMethodIdentifier(Class<?> enumType) {
        Method[] methods = enumType.getDeclaredMethods();
        String name = null;
        for (Method method : methods) {
            int mod = method.getModifiers();
            if (Modifier.isPublic(mod) && !Modifier.isStatic(mod) && !Modifier.isFinal(mod)) {
                name = method.getName();
                break;
            }
        }
        return name;
    }
}

例:

public enum Foo {
    ONE("eins"), TWO("zwei"), THREE("drei");

    private String value;

    private Foo(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

EnumUtil.from(Foo.class, "drei")返回Foo.THREE,因为它将getValue用于匹配“ drei”,这是唯一的公共方法,不是Foo中的final和static方法。例如,如果Foo有更多的公共方法,而不是final方法和非静态方法,getTranslate该方法返回“ drei”,则可以使用其他方法:EnumUtil.from(Foo.class, "drei", "getTranslate")


1

Kotlin解决方案

创建一个扩展名,然后呼叫valueOf<MyEnum>("value")。如果类型无效,您将得到null并必须处理它

inline fun <reified T : Enum<T>> valueOf(type: String): T? {
    return try {
        java.lang.Enum.valueOf(T::class.java, type)
    } catch (e: Exception) {
        null
    }
}

另外,您可以设置默认值,调用valueOf<MyEnum>("value", MyEnum.FALLBACK),并避免返回空响应。您可以扩展特定的枚举以使默认枚举为自动

inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T {
    return try {
        java.lang.Enum.valueOf(T::class.java, type)
    } catch (e: Exception) {
        default
    }
}

或者,如果您两者都想要,则进行第二个:

inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T = valueOf<T>(type) ?: default

您认为您的答案会在这里拥有更好的家吗?stackoverflow.com/questions/28548015/...
nabster

0

我喜欢使用这种过程将命令作为字符串解析为枚举。我通常将其中一个枚举称为“未知”,因此在未找到其他枚举(即使在不区分大小写的基础上)而不是null(表示没有值)的情况下将其返回会有所帮助。因此,我使用这种方法。

static <E extends Enum<E>> Enum getEnumValue(String what, Class<E> enumClass) {
    Enum<E> unknown=null;
    for (Enum<E> enumVal: enumClass.getEnumConstants()) {  
        if (what.compareToIgnoreCase(enumVal.name()) == 0) {
            return enumVal;
        }
        if (enumVal.name().compareToIgnoreCase("unknown") == 0) {
            unknown=enumVal;
        }
    }  
    return unknown;
}

-1

获取枚举名称的最快方法是在应用程序启动时创建枚举文本和值的映射,并通过函数Blah.getEnumName()来获取名称:

public enum Blah {
    A("text1"),
    B("text2"),
    C("text3"),
    D("text4");

    private String text;
    private HashMap<String, String> map;
    Blah(String text) {
    this.text = text;
    }

    public String getText() {
      return this.text;
    }

    static{
      createMapOfTextAndName();
    }

    public static void createMapOfTextAndName() {
        map = new HashMap<String, String>();
        for (Blah b : Blah.values()) {
             map.put(b.getText(),b.name());
        }
    }
    public static String getEnumName(String text) {
        return map.get(text.toLowerCase());
    } 
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.