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>.
* 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>.
*
* @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;
}
}
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();
}
}
1
使用来自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);
}
}
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;
}
}
15
这是一个可以为任何枚举执行此操作的方法,并且不区分大小写 .
/**
* 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()
));
}
0
由于尚未提及 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);
}
}
}
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;
}
}
2
这是我使用的一个漂亮的实用程序:
/**
* 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);
}
24 回答
另一个实用程序以相反方式捕获使用标识Enum的值,而不是其名称 .
例:
EnumUtil.from(Foo.class, "drei")
返回Foo.THREE
,因为它将使用getValue
来匹配"drei",这是唯一的公共,而不是Foo中的final和非静态方法 . 如果Foo具有多个on public,而不是final和not static方法,例如,getTranslate
返回"drei",则可以使用另一种方法:EnumUtil.from(Foo.class, "drei", "getTranslate")
.另一种方法是使用Enum的隐式静态方法
name()
. name将返回用于创建该枚举的确切字符串,该字符串可用于检查提供的字符串:测试:
System.out.println(Blah.getEnum("B").name());
灵感:10 Examples of Enum in Java
添加到最受好评的答案,有用的实用程序......
valueOf()
在不喜欢其输入的情况下抛出两个不同的异常 .IllegalArgumentException
NullPointerExeption
如果您的要求不能保证您的String肯定会与枚举值匹配,例如,如果String数据来自数据库并且可能包含旧版本的枚举,那么您将需要处理这些经常...
所以这里是我编写的一个可重用的方法,它允许我们定义一个默认的Enum,如果我们传递的String不匹配则返回 .
像这样用它:
您可能需要这样:
还有一个补充:
这将通过字符串化的枚举名称返回值,例如如果您在fromEnumName中提供“PERSON”,它将返回Enum的值,即“Person”
我的2美分:使用Java8 Streams检查确切的字符串:
编辑
将函数重命名为
valueOf()
(或fromString()
),因为使用该约定命名它,您将从Java语言本身获得一些好处;例如:java.lang.Enum
定义了几种有用的方法,可用于Java中的所有枚举类型:您可以使用
name()
方法获取任何枚举常量的名称 . 用于编写枚举常量的字符串文字是它们的名称 .类似地,
values()
方法可用于从Enum类型获取所有Enum常量的数组 .对于提出的问题,您可以使用
valueOf()
方法将任何String转换为Java中的Enum常量,如下所示 .在此代码段中,
valueOf()
方法返回一个Enum常量Gender.MALE,在其上调用name返回"MALE"
.是的,
Blah.valueOf("A")
会给你Blah.A
.请注意,名称必须完全匹配,包括大小写:
Blah.valueOf("a")
和Blah.valueOf("A ")
都抛出IllegalArgumentException
.静态方法
valueOf()
和values()
是在编译时创建的,不会出现在源代码中 . 但它们确实出现在Javadoc中;例如,Dialog.ModalityType显示了这两种方法 .要添加到先前的答案,并解决一些关于null和NPE的讨论,我正在使用Guava Optionals来处理缺席/无效案例 . 这适用于URI /参数解析 .
对于那些不知道的人,这里有一些关于使用Optional避免null的更多信息:https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional
如果你没有't want to write your own utility use Google'的guava库:
与内置的java函数不同,它让你检查Blah中是否存在A并且不会抛出异常 .
你也应该小心你的情况 . 让我解释一下:做
Blah.valueOf("A")
工作,但是Blah.valueOf("a")
将不起作用 . 然后Blah.valueOf("a".toUpperCase(Locale.ENGLISH))
再次起作用 .edit
基于tc. comment和java docs将
toUpperCase
更改为toUpperCase(Locale.ENGLISH)
edit2 在Android上你应该使用Locale.US,作为sulai points out .
使用
Blah.valueOf(string)
是最好的,但您也可以使用Enum.valueOf(Blah.class, string)
.在Java 8中,静态Map模式更容易,是我的优先方法 . 如果你想使用Enum with Jackson,你可以覆盖toString并使用它代替名称,然后用
@JsonValue
注释Apache的commons-lang库有一个静态函数org.apache.commons.lang3.EnumUtils.getEnum,它将String映射到你的Enum类型 . 基本上和Geoffreys一样的答案,但为什么在野外已经存在的时候自己滚动 .
我喜欢使用这种过程将命令作为字符串解析为枚举 . 我通常将其中一个枚举称为“未知”,因此当找不到其他枚举时(即使基于不区分大小写)而不是null(这意味着没有值),它会有所帮助 . 因此我使用这种方法 .
使用Guava库的解决方案 . 方法getPlanet()不区分大小写,因此getPlanet(“MerCUrY”)将返回Planet.MERCURY .
使用来自Joshua Bloch,Effective Java的模式:
(为简洁起见,简化)
另见:
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
O(1)方法受益于使用散列映射的thrift生成的代码 .
这是一个可以为任何枚举执行此操作的方法,并且不区分大小写 .
由于尚未提及
switch
-version,我将其介绍(重用OP的枚举):由于这不会给
valueOf(String name)
方法带来任何附加值,因此如果我们想要有不同的行为,那么定义一个额外的方法才有意义 . 如果我们不想提出IllegalArgumentException
,我们可以将实现更改为:通过提供默认值,我们保持contract的contract而不会以这种方式抛出
IllegalArgumentException
,在任何情况下都不会返回null
. 因此,如果名称为null
,则抛出NullPointerException
,如果defaultValue
为null
,则抛出default
. 这就是valueOfOrDefault
的工作方式 .这种方法采用了
Map
-Interface的设计,它提供了Java 8中的方法Map.getOrDefault(Object key, V defaultValue)
.在Java 8或更高版本中,使用Streams:
如果文本与枚举值不同,则为另一种解决方案:
这是我使用的一个漂亮的实用程序:
然后在我的枚举类中,我通常会这样做以节省一些输入:
如果您的枚举不是全部大写,只需更改
Enum.valueOf
行即可 .太糟糕了,因为
T
被删除,所以不能使用T.class
Enum.valueOf
.关于什么?