如何从Java中的字符串值中获取枚举值
Posted
技术标签:
【中文标题】如何从Java中的字符串值中获取枚举值【英文标题】:How to get an enum value from a string value in Java 【发布时间】:2010-10-10 21:42:50 【问题描述】:假设我有一个枚举,它只是
public enum Blah
A, B, C, D
我想找到一个字符串的枚举值,例如"A"
,即Blah.A
。怎么可能做到这一点?
Enum.valueOf()
是我需要的方法吗?如果是这样,我将如何使用它?
【问题讨论】:
【参考方案1】:是的,Blah.valueOf("A")
会给你Blah.A
。
请注意,名称必须完全匹配,包括大小写:Blah.valueOf("a")
和 Blah.valueOf("A ")
都抛出 IllegalArgumentException
。
静态方法valueOf()
和values()
在编译时创建,不会出现在源代码中。不过,它们确实出现在 Javadoc 中;例如,Dialog.ModalityType
显示了这两种方法。
【讨论】:
作为参考,Blah.valueOf("A")
方法区分大小写并且不允许多余的空格,因此@JoséMi 在下面提出了替代解决方案.
@Michael Myers,由于这个答案是迄今为止投票最多的,我是否应该理解将枚举及其 String 值定义为完全相同的好习惯?
@KevinMeredith:如果你的意思是toString()
值,不,我不会这么说。 name()
将为您提供枚举常量的实际定义名称,除非您覆盖它。
“在编译时创建并且不出现在源代码中”究竟是什么意思。 ?
@treesAreEverywhere 更具体地说,这些方法由编译器生成(或合成)。实际的enum Blah ...
定义不应尝试声明自己的values
或valuesOf
。这就像您如何编写“AnyTypeName.class”,即使您从未真正声明过“类”成员变量;编译器使这一切都可以正常工作。 (此答案可能在 3 个月后对您不再有用,但以防万一。)【参考方案2】:
文本与枚举值不一样的另一种解决方法:
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
更好。
@Sangdol 通常检查 SUN - 哎呀 - Oracle 在相同情况下所做的事情是件好事。正如Enum.valueOf() 所展示的那样,IS 是在这种情况下抛出异常的最佳实践。 因为这是一种特殊情况。 “性能优化”是编写不可读代码的糟糕借口;-)【参考方案3】:
使用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().toLowerCase(),instance);
ENUM_MAP = Collections.unmodifiableMap(map);
public static MyEnum get (String name)
return ENUM_MAP.get(name.toLowerCase());
另见:
Oracle Java Example using Enum and Map of instances
Execution order of of static blocks in an Enum type
How can I lookup a Java enum from its String value
【讨论】:
这在 Java 8 中更简单,你可以这样做:Stream.of(MyEnum.values()).collect(toMap(Enum::name, identity()))
我还建议覆盖 toString()(通过构造函数传入)并使用它而不是名称,特别是如果 Enum 与可序列化的数据,因为这使您可以控制外壳,而无需考虑 Sonar。
Static initialization is inherently synchronized,所以这里绝对没有理由使用ConcurrentHashMap
,因为地图在初始化后永远不会被修改。因此,为什么甚至例如JLS 本身中的示例使用常规的HashMap
。【参考方案4】:
这是我使用的一个漂亮的实用程序:
/**
* 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
被删除了,所以我不能将T.class
用于Enum.valueOf
。
【讨论】:
那个空的 catch 块真的让我发疯了,对不起。 @LazloBonin:异常是针对异常情况,而不是针对控制流。获取一份Effective Java 的副本。 太糟糕了!总是,总是在你可以处理的地方捕捉异常。上面的例子是一个完美的例子如何不做。为什么?所以它返回 NULL,然后调用者必须检查 NULL 或抛出 NPE。如果调用者知道如何处理这种情况,那么执行 if 与 try-catch 可能看起来更优雅,但是如果他无法处理,他必须再次传递 null 并且调用者调用者再次必须检查NULL等。 @whiskeysierra 我知道对 Java 或软件开发充满热情是一回事,但你得冷静一下。像这样出人头地/成为额外的人没有任何好处。【参考方案5】:您还应该小心处理您的案件。让我解释一下:做Blah.valueOf("A")
有效,但Blah.valueOf("a")
无效。然后Blah.valueOf("a".toUpperCase(Locale.ENGLISH))
再次起作用。
在 android 上,您应该使用 Locale.US
,如 sulai points out。
【讨论】:
警惕默认语言环境!【参考方案6】:在 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();
【讨论】:
Java 8 做了一些好事,虽然我喜欢 Streams(主要用于并发)......这实际上不是使用它们的理由。它什么都不买 OP 并且性能更差......只需将所有项目的 for/next 循环替换为相同的 Stream 版本(甚至不是并行)。对于一些条目......谁在乎但要清楚,这不是一些“因为Java 8而更好”的例子。它只是一个流畅的绿色与蓝色“不同”实现,相同的返回一个 Optional vs null (并且流畅的风格需要所有连接方法的非空返回)。【参考方案7】:这是一种可以对任何 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()
));
【讨论】:
很好地使用泛型,但不确定 IllegalArgumentException 是否真的是正确的合同。首先,查找失败完全有可能(并且预期?)......它本身不在集合中(实际上是枚举)。抛出 RuntimeException “在方法外传播 [s]”。由于这不在方法签名中 - 调用者不会期望它。最好使用 Map 构造(在未找到时返回 null)或者甚至更好... Optional.empty()。【参考方案8】:最好使用Blah.valueOf(string)
,但您也可以使用Enum.valueOf(Blah.class, string)
。
【讨论】:
【参考方案9】:我的两分钱:使用 Java 8 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 语言本身获得一些好处;例如:
-
Direct conversion of types at HeaderParam annotation
【讨论】:
【参考方案10】:如果您不想编写自己的实用程序,请使用 Google 的 guava 库:
Enums.getIfPresent(Blah.class, "A")
与内置的 Java 函数不同,它让您检查 A 是否存在于 Blah 中并且不会引发异常。
【讨论】:
【参考方案11】:您可能需要这样做:
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 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”。
【讨论】:
【参考方案12】:另一种方法是使用 Enum 的隐式静态方法name()
。 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 Examples of Enum in Java
【讨论】:
【参考方案13】:这是使用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();
【讨论】:
【参考方案14】:枚举非常有用。我一直在使用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");
【讨论】:
【参考方案15】:在 Java 8 中,静态 Map 模式更加简单,是我的首选方法。如果您想将 Enum 与 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);
【讨论】:
混淆代码竞赛亚军?我的意思是这在技术上是正确的。 :-) ...但是对于 Map 上的简单 for/next 循环来说,它是非常迟钝的——可以说,这并不比 Java 的早期版本所能提供的更好。 private static final Map为了补充前面的答案,并解决一些关于 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 的更多信息。
【讨论】:
【参考方案17】: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;
【讨论】:
【参考方案18】:一种 O(1) 方法,灵感来自 Thrift 生成的代码,该代码使用哈希图。
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;
【讨论】:
【参考方案19】:java.lang.Enum
定义了几个有用的方法,Java 中所有枚举类型都可以使用:
name()
方法来获取任何枚举常量的名称。用于编写枚举常量的字符串字面量就是它们的名字。
同样,values()
方法可用于从 Enum 类型中获取所有 Enum 常量的数组。
而对于提出的问题,您可以使用valueOf()
方法将任何String 转换为Java 中的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
在这段代码 sn-p 中,valueOf()
方法返回一个 Enum 常量,Gender.MALE,调用名称返回 "MALE"
。
【讨论】:
【参考方案20】:Apache 的commons-lang 库有一个静态函数org.apache.commons.lang3.EnumUtils.getEnum,它将一个字符串映射到你的枚举类型。与Geoffrey Zheng's 的答案基本相同,但是当它已经在野外时,没有任何必要推出自己的答案。
【讨论】:
【参考方案21】:用途:
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();
【讨论】:
【参考方案22】:添加到Michael Myers' answer,使用有用的实用程序...
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.THINGTWO
valueOf("THINGZERO" , MYTHINGS.THINGONE);//returns MYTHINGS.THINGONE
【讨论】:
【参考方案23】:由于尚未提及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)
的contract 而不会以这种方式抛出IllegalArgumentException
,在任何情况下都不会返回null
。因此,如果名称是 null
,我们会抛出 NullPointerException
,如果 defaultValue
是 null
,则抛出 default
。这就是valueOfOrDefault
的工作原理。
这种方法采用Map
-Interface 的设计,该接口提供了一种方法Map.getOrDefault(Object key, V defaultValue)
,从Java 8 开始。
【讨论】:
【参考方案24】:我正在寻找一个答案来找到“blah”名称而不是它的值(不是文本)。基于Manu's answer,我发现这段代码很有用:
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;
【讨论】:
【参考方案25】:另一个以相反方式捕获的实用程序。使用标识该 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”,这是唯一的public,不是Foo 中的final 和静态方法。
如果 Foo 有多个 public、not final 和 not static 方法,例如返回“drei”的getTranslate
,则可以使用其他方法:EnumUtil.from(Foo.class, "drei", "getTranslate")
。
【讨论】:
【参考方案26】:枚举 valueOf()
枚举类在编译时会自动获取类中的静态 valueOf() 方法。 valueOf() 方法可用于获取给定 String 值的枚举类的实例。
例如:
public class Main
public static void main(String[] args) throws Exception
System.out.println(Strings.TWO.name());
enum Strings
ONE, TWO, THREE
【讨论】:
【参考方案27】:Blah.valueOf("A")
是您要查找的语句,但请记住,这是 CASE SENSITIVE,因此 Blah.valueOf("a") 将不起作用并会生成异常。
【讨论】:
【参考方案28】:我喜欢使用这种过程将命令作为字符串解析为枚举。我通常将其中一个枚举设置为“未知”,因此在找不到其他枚举(即使在不区分大小写的情况下)而不是 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;
【讨论】:
【参考方案29】: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
【讨论】:
【参考方案30】:获取枚举名称的最快方法是在应用程序启动时创建枚举文本和值的映射,并调用函数 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());
【讨论】:
以上是关于如何从Java中的字符串值中获取枚举值的主要内容,如果未能解决你的问题,请参考以下文章