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

Malachi 1890 java enums

说我有一个只是的枚举

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

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

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

Michael Myer.. 2167

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

请注意,名称必须是完全匹配,包括大小写:Blah.valueOf("a")并且Blah.valueOf("A ")两者都抛出IllegalArgumentException.

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

  • 作为参考,`Blah.valueOf("A")`方法是***区分大小写***并且不容忍无关的空白,因此@JoséMi提出了下面提出的替代解决方案. (97认同)
  • @treesAreEverywhere更具体地说,这些方法由编译器_generated_(或_synthesized_).实际的`enum Blah {...}`定义不应该试图声明它自己的`values`或`valuesOf`.这就像你怎么写"AnyTypeName.class",即使你从未真正宣布过"类"成员变量; 编译器使它全部正常工作.(这个答案可能在3个月后对你不再有用,但为了以防万一.) (7认同)
  • @KevinMeredith:如果你的意思是`toString()`值,不,我不会这么说.`name()`将获取枚举常量的实际定义名称,除非您覆盖它. (4认同)
  • @Michael Myers,由于这个答案是迄今为止投票最多的,我应该理解定义枚举及其String值完全相同是一种好习惯吗? (3认同)
  • 你究竟是什么意思"是在编译时创建的,不会出现在源代码中." ? (3认同)

JoséMi.. 826

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

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;
    }
}

  • `throw new IllegalArgumentException("No constant with text"+ text +"found")`将比`return null`更好. (387认同)
  • @Sangdol通常检查SUN - oops - Oracle在相同的情况下做什么是一件好事.并且[Enum.valueOf()](http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Enum.html#valueOf)正在显示它******最佳实践在这种情况下抛出异常.*因为*这是一种特殊情况."性能优化"是编写不可读代码的不良借口;-) (57认同)
  • @Sangdol可以*你*我们为什么回到null更好? (11认同)
  • @whiskeysierra Jon Skeet不同意这一点.http://stackoverflow.com/questions/1167982/check-if-enum-exists-in-java (7认同)
  • 那么,您也可以使用@Nullable注释使其"可读";-) (5认同)
  • @Tyzoid @raudi公平地说,特别是如果你要编写代码以供其他人使用,那么适当的做法就是``Queue`接口与`remove`对`poll`的做法 - 有两个该方法的一个版本,一个返回`null`(一个非常可预测和常见的)失败,一个抛出异常,然后让谁使用它根据较大的应用程序保证什么决定使用什么. (4认同)
  • 为了公平对待Jon Skeet,他回答的问题是如何在不抛出异常的情况下做到这一点.他回答问题的事实并不意味着他认为这是个好主意.@SanghyunLee (3认同)
  • 该注释是关于实际捕获异常以确定字符串是否表示有效枚举值的建议答案.对于这样的用例,您可能需要第二种方法(例如isValid). (2认同)
  • @Tyzoid:我没有说这是错的我甚至没有说这是不好的做法,我只是说抛出异常看起来更合适.想想调用者必须做什么:如果返回null,那么必须在每次调用之后检查返回值,除非你想要捕获NPE,你不应该这样;-).现在看看如果抛出异常会发生什么:调用者可以决定他想要捕获它的级别:全局捕获异常,全局捕获特定的异常或捕获单个调用的特定异常或其任何组合.肯定好多了...... (2认同)
  • 我想`if(text == null)return null;`优于`if(text!= null){....} return null`。第一种方法更容易理解。 (2认同)

Geoffrey Zhe.. 118

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

/**
 * 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.valueOfT被删除.

  • 那个空的挡板确实让我疯了,抱歉. (173认同)
  • 可怕!总是,**总是**捕捉异常,你可以处理它们.上面的例子是一个完美的例子**如何不做**.为什么?所以它返回NULL,然后调用者必须检查NULL或抛出NPE.如果调用者知道如何处理这种情况,那么执行if与try-catch可能看起来更优雅,**但是如果他无法处理他必须再次传递null并且调用者的调用者**再次**必须检查NULL等等. (44认同)
  • @LazloBonin:异常是针对特殊情况而非控制流程.获取[Effective Java]的副本(http://java.sun.com/docs/books/effective/). (29认同)
  • 如果要使用的Java API抛出异常并且您不希望代码抛出异常,则可以像这样吞下异常,或者从头开始重写逻辑,这样就不会抛出异常.吞噬异常通常是较小的邪恶. (10认同)
  • 为了公平对待上面的解决方案,确实有一些用例要求您返回null而不是抛出IllegalArgumentException并打破程序流,例如,在Web服务模式和数据库模式之间映射枚举,其中它们并不总是一个-to-之一.但是,我同意不应该将catch块留空.放一些像log.warn这样的代码用于跟踪目的. (10认同)
  • 我错过了什么吗?与简单使用相比,上述方法的附加值是什么:`MyEnum.valueOf(name)`? (4认同)
  • @urig他们不区分大小写,不像`valueOf` (2认同)
  • 如果您要为不区分大小写的比较编写单独的例程,那么为什么不使用`String.equalsIgnoreCase`而不是这个硬编码的`toUpperCase`进行不区分大小写的检查? (2认同)

Darrell Teag.. 85

使用来自Joshua Bloch,Effective Java的模式:

(为简洁起见,简化)

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

另见:

使用Enum和实例映射的Oracle Java示例

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

如何从String值中查找Java枚举

  • 这在Java 8中甚至可以更简单:`Stream.of(MyEnum.values()).collect(toMap(Enum :: name,identity()))`我还建议覆盖toString()(传入构造函数)并使用它代替名称,特别是如果Enum与可序列化数据相关联,因为这可以让你控制套管而不让Sonar适合. (8认同)
  • [静态初始化本质上是同步的](https://docs.oracle.com/javase/specs/jls/se10/html/jls-12.html#jls-12.4.2),所以绝对没有理由使用`ConcurrentHashMap `这里,初始化之后永远不会修改地图.因此,为什么即使例如JLS中的示例本身也使用常规的"HashMap". (8认同)
  • 若约书亚布洛赫说,那么这是唯一的出路:-).遗憾的是我总是要向下滚动. (4认同)
  • 如果你打算把它放在一个`unmodifiableMap`中,那么从'ConcurrentHashMap`开始就没有任何好处.只需使用`HashMap`.(如果你有番石榴的'ImmutableMap`那么我建议改为!) (3认同)

João Portela.. 74

你也应该小心你的情况.让我解释一下:做Blah.valueOf("A")工作,但Blah.valueOf("a")不行.然后再次Blah.valueOf("a".toUpperCase(Locale.ENGLISH))工作.

编辑
已更改toUpperCasetoUpperCase(Locale.ENGLISH)基于tc.评论java文档

edit2 在Android上你应该使用Locale.US,正如sulai指出的那样.

  • 警惕默认的语言环境! (6认同)
  • 对于那些Android用户,我想指出[Android文档](http://developer.android.com/reference/java/util/Locale.html#default_locale)明确鼓励使用`Locale.US `用于机器可读输入/输出. (3认同)
  • @Trengot是的,不幸的是.土耳其是一个很好的例子.将此与Java对默认字符集的破坏处理(默认为Windows上的拉丁语而不是Unicode)相结合,您会发现使用接受字符集或语言环境的默认版本的方法几乎总是不安全的.您应该几乎总是明确定义它们. (2认同)

Patrick Arne.. 38

这是一个可以为任何Enum执行此操作的方法,并且不区分大小写.

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


Peter Lawrey.. 35

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

  • 嗨@PeterLawrey,我想从String public enum ObjectType {PERSON("Person")public String parameterName中获取一个枚举; ObjectType(String parameterName){this.parameterName = parameterName; public String getParameterName(){return this.parameterName; public static ObjectType fromString(String parameterName){if(parameterName!= null){for(ObjectType objType:ObjectType.values()){if(parameterName.equalsIgnoreCase(objType.parameterName)){return objType; 返回null; }} (2认同)

Hans Schreud.. 32

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


Andrejs.. 28

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

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

与内置的java函数不同,它让你检查Blah中是否存在A并且不会抛出异常.

  • 可悲的是,这将返回一个google Optional而不是java Optional (7认同)

Manu.. 25

我的2美分:使用Java8 Streams +检查确切的字符串:

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注释中直接转换类型


Murtaza Kanc.. 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",它将返回Enum的值,即"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

灵感:10个Java中的Enum示例

  • 这实际上是`valueOf`为你做的事情.这种静态方法不提供任何额外的,异常等等.那么if/else结构是非常危险的......任何添加的新枚举常量都会导致此方法无变化地中断. (7认同)
  • `name()`不是静态的. (2认同)

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


Novaterata.. 8

在Java 8中,静态Map模式更容易,是我的优先方法.如果你想使用Enum with Jackson,你可以覆盖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);
    }
}


tom.. 7

要添加到先前的答案,并解决围绕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();
        }
    }
}

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


Prasobh.Koll.. 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;
}


Sisyphus.. 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;
        }

}


归档时间:

查看次数:

1063121 次

最近记录:

1 年 前