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

假设我有一个枚举

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

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

#0是我需要的方法吗?如果是,我将如何使用它?

1510776 次浏览

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

请注意,名称必须是确切匹配,包括case:Blah.valueOf("a")Blah.valueOf("A ")都抛出IllegalArgumentException

静态方法valueOf()values()是在编译时创建的,不会出现在源代码中。不过,它们确实出现在Javadoc中;例如,#2显示了这两个方法。

你也应该小心你的情况。让我解释一下:做Blah.valueOf("A")有效,但Blah.valueOf("a")不起作用。然后Blah.valueOf("a".toUpperCase(Locale.ENGLISH))也会起作用。

在Android上,您应该使用#0作为苏莱指出

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

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

/*** 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.class作为Enum.valueOf,因为T被擦除了。

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

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

另一种方法是使用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执行此操作的方法,并且不区分大小写。

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

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

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

与内置的Java函数不同,它允许您检查A是否存在于Blah中并且没有抛出异常。

这是一个使用番石榴库的解决方案。方法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();}}

为了补充前面的答案,并解决一些关于null和NPE的讨论,我使用番石榴选项来处理缺席/无效的情况。这对于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();}}}

对于那些不知道的人,这里有一些关于使用可选的避免null的更多信息。

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

  • 您可以使用name()方法来获取任何枚举常量的名称。用于编写枚举常量的字符串文字是它们的名称。
  • 类似地,values()方法可用于从Enum类型获取所有Enum常量的数组。
  • 对于所问问题,您可以使用valueOf()方法将任何String转换为Java中的枚举常量,如下所示。
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"

您可能需要这样做:

public enum ObjectType {PERSON("Person");
public String parameterName;
ObjectType(String parameterName) {this.parameterName = parameterName;}
public String getParameterName() {return this.parameterName;}
// From the String method, it will return you the Enum for the provided input stringpublic 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”。

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

Apache的公共空间库有一个静态函数org.apache.commons.lang3.EnumUtils.get枚举,它将一个String映射到您的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中唯一的公共方法,而不是最终方法,也不是静态方法。如果Foo有不止一个公共的、不是最终的、不是静态的方法,例如,getTranslate返回“drei”,可以使用另一个方法:EnumUtil.from(Foo.class, "drei", "getTranslate")

使用Joshua Bloch有效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().toLowerCase(),instance);}ENUM_MAP = Collections.unmodifiableMap(map);}
public static MyEnum get (String name) {return ENUM_MAP.get(name.toLowerCase());}}

另见:

OracleJava实例枚举和映射的示例

枚举类型中静态块的执行顺序

如何从其String值查找Java枚举

我喜欢使用这种过程将命令作为字符串解析为枚举。我通常将其中一个枚举作为“未知”,因此当其他枚举找不到时(即使不区分大小写)而不是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;}

添加到迈克尔·迈尔斯的回答,使用有用的实用程序…

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

  • IllegalArgumentException
  • NullPointerExeption

如果你的需求是这样的,你不能保证你的String一定会匹配枚举值,例如,如果String数据来自数据库并且可能包含旧版本的枚举,那么你需要经常处理这些。

所以这是我写的一个可重用的方法,它允许我们定义一个默认的枚举,如果我们传递的字符串不匹配,则返回。

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.THINGTWOvalueOf("THINGZERO" , MYTHINGS.THINGONE);//returns MYTHINGS.THINGONE}

在Java8中,静态Map模式更简单,是我的首选方法。如果你想在Jackson中使用Enum,你可以重写toString并使用它而不是name,然后用@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@Overridepublic String toString() {return value;}
public static MyEnumForJson fromValue(String value){return MAP.get(value);}}

我的两分钱:使用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注释中直接转换类型

在Java8或更高版本中,使用

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

用途:

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

由于还没有提到switch版本,我介绍了它(重用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。因此,如果名称是null,我们抛出NullPointerException,如果defaultValuenull,我们抛出default。这就是valueOfOrDefault的工作原理。

这种方法采用Map接口的设计,它提供了Java8的方法Map.getOrDefault(Object key, V defaultValue)

获取枚举名称的最快方法是在应用程序启动时创建枚举文本和值的映射,并调用函数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());}}

枚举非常有用。我一直在使用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");

静态编程语言解决方案

创建一个扩展名,然后调用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

我正在寻找一个答案来查找“blah”名称而不是它的值(而不是文本)。基于马努的回答,我发现这段代码很有用:

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 valueOfCode(String blahCode) throws IllegalArgumentException {Blah blah = Arrays.stream(Blah.values()).filter(val -> val.name().equals(blahCode)).findFirst().orElseThrow(() -> new IllegalArgumentException("Unable to resolve blah: " + blahCode));
return blah;}

}

Enum value Of()

枚举类在编译时自动获取类中的静态value eOf()方法。value eOf()方法可用于获取给定String值的枚举类实例。

例如:

public class Main {public static void main(String[] args) throws Exception {System.out.println(Strings.TWO.name());}enum Strings {ONE, TWO, THREE}}
public enum ToggleStatusUpdate {OFF("off", 1),ON("on", 2);    
private final String name;private final int position;    
private ToggleStatusUpdate(String name, int position) {this.name = name;this.position = position;}
public String getName() {return name;}
public int getPosition() {return position;}    
public static int getPositionForName(String name) {for(ToggleStatusUpdate toggleStatusUpdate : ToggleStatusUpdate.values()) {if (toggleStatusUpdate.getName().equals(name)) {return toggleStatusUpdate.getPosition();}}return -1;}
public static void main(String[] args) {System.out.println(ToggleStatusUpdate.getPositionForName("off"));}}

使用StreamsJava8的答案和注释的组合。它为查找创建一个静态Map,并有机会使用默认值,以防止空检查。

public enum Blah {A, B, C, D, INVALID
private static final Map<String, Blah> ENUM_MAP = Stream.of(Blah.values()).collect(Collectors.toMap(Enum::name, Function.identity()));
public static Blah of(final String name) {return ENUM_MAP.getOrDefault(name, INVALID);}}
// e.g.Blah.of("A");A
Blah.of("X")INVALID
public enum DivisionType {DEFAULT(0){@Overridepublic void sort(List<SigInUserDto> SigInUserDtos) {SigInUserDtos.sort(new SigInUserCoinsQueueComparator());}},ASSIGNPOINTS(1) {@Overridepublic void sort(List<SigInUserDto> SigInUserDtos) {SigInUserDtos.sort(new SigInUserPointsComparator());}},ASSIGNEVENORDER(2) {@Overridepublic void sort(List<SigInUserDto> SigInUserDtos) {SigInUserDtos.sort(new SigInUserOrderCountComparator());}};
public final Integer label;
DivisionType(Integer label) {this.label = label;}
public static DivisionType getTypeById(Integer id) {for (DivisionType value : DivisionType.values()) {if (value.label == id) {return value;}}return DEFAULT;}
public abstract void sort(List<SigInUserDto> SigInUserDtos);}

使用枚举:DivisionType.getTypeByIdobject.getBalancingTypeId()

这里,在每个枚举匹配下实现(重载)sort()函数。因此,基于对象“object.getBalancingTypes Id(). intValue()”匹配值,调用并排序特定的枚举匹配。