假设我有一个枚举
public enum Blah {
A, B, C, D
}
我想找到一个字符串的枚举值,例如"A",它是Blah.A。怎么可能做到这一点?
我需要的方法是Enum.valueOf()吗?如果是的话,我怎么用这个?
是的,Blah.valueOf("A")会给你Blah.A。
注意,名称必须完全匹配,包括case:Blah.valueOf("A")和Blah.valueOf("A")都抛出IllegalArgumentException。
静态方法valueOf()和values()是在编译时创建的,不会出现在源代码中。不过,它们确实出现在javadoc中;例如,Dialog.ModalityType显示了这两种方法。
作为参考,Blah.valueOf("A")方法区分大小写,不允许有外来空白,因此下面由@jos&233;mi提出的替代解决方案。
@Michael Myers,因为这个答案是迄今为止投票最多的,我应该理解定义一个枚举及其字符串值完全相同是一个好的实践吗?
@凯文梅雷迪思:如果你是指toString()的价值,不,我不会这么说。name()将获取枚举常量的实际定义名称,除非您重写它。
您所说的"在编译时创建,而不出现在源代码中"是什么意思?
@实际上,更具体地说,这些方法是由编译器生成(或合成)的。实际的enum Blah {...}定义不应试图声明自己的values或valuesOf。这就像你如何写"anytypename.class",即使你从未真正声明过"class"成员变量;编译器使它一切正常工作。(3个月后,这个答案可能对您不再有用,但以防万一。)
很好的答案——另外,我发现在Enums中添加一些小的helper方法有很大帮助…例如,如果您在构造函数中创建一个小写项的静态映射,那么您可以添加一个以不区分大小写的方式查找枚举的方法,或者将底线转换为空格,这样用户输入(如"second entry")可以映射到枚举第二个项。
为什么@brett的评论有这么多选票?当然,它是区分大小写的,不能容忍外来的空白,任何其他东西都是疯狂的。
@Nemetroid没有那么疯狂,因为名称中不允许有空格,并且所有枚举名称都是按约定加起来的。因此,由于结果保持唯一,因此可以使用容错查找方法。但是,用户可能需要一些更为宽容的东西,因此最好提供一个规范的严格版本(还有其他问题,比如大写字母对区域敏感等等)。
向上投票,但如果提到enum::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;
}
}
throw new IllegalArgumentException("No constant with text" + text +" found")比return null好。
@威士忌商乔恩·斯基特不同意这一点。stackoverflow.com/questions/1167982/…
@桑多尔,你能启发我们为什么还空更好吗?
该注释是关于实际捕获异常以确定字符串是否表示有效枚举值的建议回答。对于这样的用例,您可能需要第二个方法(例如isvalid)。
@桑多尔通常是一个好事情,检查什么太阳-糟糕-甲骨文是在同样的情况下。正如Enum.ValueOf()所示,在这种情况下引发异常是最佳实践。因为这是一种特殊情况。""性能优化"是编写不可读代码的错误借口;-)
好吧,还可以使用@nullable注释使其"可读";-)
好的,要将字符串转换为枚举常量,最好是在空或不匹配的情况下抛出异常,与valueof的情况相同。但是,请考虑如何实现一个方法来测试枚举常量是否使用了字符串…关于stackoverflow.com/a/12659023/744133上所有这些的示例
关于错误处理,它始终取决于信息的来源。如果您的值来自您无法控制的外部源(用户输入…),请捕获错误并在可能的情况下显示一些有意义的消息。如果传递给valueof的值来自于您自己的内部代码,那么您应该捕获错误并很难失败(日志和崩溃),您可能有一个bug,可以修复它。
我有一个非常愚蠢的问题…在fromString方法中,在执行equalSignoreCase之后,就有了b.text。文本是枚举类的私有成员。如何访问它?
@Jan:因为代码本身在枚举类中,当然,它对该类的所有属性和方法都具有可见性。
@在这种情况下,Raudi更喜欢使用null,因为当我获取值时,我发现检查if(returnval == null)比捕获异常更实用。它在理想情况下也能更好地工作:如果结果不匹配,返回空结果是否更有意义?或者抛出一个错误?我认为返回空结果更有意义。
@泰佐伊德:我没有说这是错的,我甚至没有说这是不好的做法,我只是说抛出异常看起来更合适。考虑调用者必须做什么:如果返回了空值,那么在每次调用之后都必须检查返回值,除非您想捕获NPE,否则不应该;-)。现在看看如果抛出异常会发生什么:调用者可以决定要捕获它的级别:全局捕获异常、全局捕获特定异常或在单个调用或其任意组合上捕获特定异常。当然更好用…
@公平地说,tyzoid@raudi,特别是如果您编写代码以供持久使用和供其他人使用,那么要做的适当的事情是,像Queue接口与remove和poll所做的那样,它有两个版本的方法,一个在(非常可预测和常见的)失败时返回null,另一个则抛出一个例外,然后让使用它的人根据更大的应用程序需要决定使用什么。
我想if (text == null) return null;比if (text != null) { ....} return null好。第一种方法更容易理解。
"真糟糕"—doug lea code.google.com/p/guava libraries/wiki/…
如果向fromString()传递NULL,text.equalsIgnoreCase(b.text)可能引发空指针异常,而b.text.equalsIgnoreCase(text)不会(给定列出的枚举实例)。
@古斯,请在你说有错误的那句之前读两行:if (text != null) {…
抱歉,写信给法斯特…这不是错误。可以避免空检查。这就像"foo".equals(bar)而不是bar.equals("foo")一样。
@jos&233;mi也可以重写默认toString()并使其返回"text"。
不需要添加text字段和getText()方法,因为代码可以很容易地使用自动生成的name()方法。也可以编写适用于任何枚举类型的public static > com.mylibs.Enums.fromString(E enumType, String s)。
在许多情况下,另一种选择是为枚举指定一个显式的未知值,这样可以避免NPE,并且仍然能够检查未知值。
公平地说,乔恩·斯基特回答的问题是如何做到这一点而不抛出和捕获异常。他按要求回答问题并不意味着他相信这是个好主意。@ SanghyunLee
值得一提的是,Kotlin…The valueOf() method throws an IllegalArgumentException if the specified name does not match any of the enum constants defined in the class.。
我使用的是一个漂亮的实用程序:
/**
* A common method for all enums since they can't have another base class
* @param Enum type
* @param c enum type. All enums must be all caps.
* @param string case insensitive
* @return corresponding enum, or null
*/
public static > T getEnumFromString(Class 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不是全部大写,只需更改Enum.valueOf行即可。
太糟糕了,我不能用T.class代替Enum.valueOf,因为T被删除了。
对不起,那个空的挡块真让我抓狂。
@Lazlobonin:例外情况是针对特殊情况,而不是针对控制流。给自己一个有效的Java副本。
如果您想使用的Java API抛出异常,并且不希望代码抛出一个异常,您可以像这样吞下异常,或者从头开始重写逻辑,这样就不会首先抛出异常。吞下例外往往是较小的邪恶。
好可怕!总是,总是在可以处理的地方捕获异常。上面的例子是一个如何避免的完美例子。为什么?所以它返回空值,然后调用者必须检查空值或者抛出一个NPE。如果调用者知道如何处理这种情况,那么执行if与try catch可能看起来更优雅一些,但是如果他不能处理,他必须再次传递空值,并且调用者的调用者必须再次检查空值等。
为了公平起见,确实有一些用例要求您返回空值,而不是抛出IllegalArgumentException并中断程序流,例如,在Web服务模式和数据库模式之间映射枚举,其中它们并不总是一对一的。但是,我同意catch块永远不应该是空的。放置一些代码,如log.warn或其他用于跟踪的代码。
绝对!记录异常是肯定的。但我同意接受例外。
现在我就用番石榴的遗数。注意无效输入的不同处理:getIfPresent返回Optional.absent(),这是我喜欢使用的;而valueOfFunction().apply()返回null。
当您希望编写一个静态方法来测试字符串是否与枚举实例匹配时,问题就会出现。对不同枚举值进行测试的唯一方法是实际调用函数的valueof。如果它抛出,则结果为假。
我错过什么了吗?与简单使用的方法相比,上述方法的附加值是多少:MyEnum.valueOf(name)?
@Urig他们不区分大小写,不像valueOf。
如果您要为不区分大小写的比较编写一个单独的例程,那么为什么不真正使用String.equalsIgnoreCase而不是这个硬编码的toUpperCase来进行不区分大小写的检查呢?
相当于apache common的enumutils getenum方法
@pjklauser no,enumutils的getEnum方法不执行不区分大小写的查找。
我喜欢这个实用工具。我们添加了一个"default"参数,以防无法确定枚举:final@nullable t def
现在是一个侧面讨论,但是…更好的做法是返回一个可选的,如果这是什么是预期的(例如,可以合理地是"未知/未定义")。然后NPE就消失了,但是查找失败并没有返回异常作为控制流的一种方式。
你也应该小心处理你的案件。让我解释一下:做Blah.valueOf("A")是可行的,但Blah.valueOf("A")是行不通的。然后,Blah.valueOf("a".toUpperCase(Locale.ENGLISH))又会起作用。
编辑基于tc将toUpperCase改为toUpperCase(Locale.ENGLISH)。注释与Java文档
编辑2苏莱指出,在安卓系统上,你应该使用Locale.US。
注意默认区域设置!
对于Android用户,我想指出的是,Android文档明确鼓励使用Locale.US进行机器可读的输入/输出。
大写字母在不同的地方不同吗?
Trengot是的。
@特伦戈是的,很不幸。土耳其就是一个很好的例子。将此与Java对默认字符集的默认处理(默认为Windows上的拉丁文而不是Unicode)相结合,您将发现使用接受字符集或区域设置的方法的默认版本几乎是不安全的。您几乎应该总是明确地定义它们。
不确定Java的"默认"字符集"本身"是"坏的",但默认为UTF-8代替重写(应该做的总是明确的)会为通常不能理解字符集概念的初级程序员提供更好的系统。
使用Joshua Bloch的模式,有效的Java:
(为了简洁而简化)
enum MyEnum {
ENUM_1("A"),
ENUM_2("B");
private String name;
private static final Map 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 map = new ConcurrentHashMap();
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示例
枚举类型中静态块的执行顺序
如何从字符串值中查找JavaEnUM
如果约书亚·布洛克说了,那么这是唯一的出路。很遗憾,我总是要向下滚动。
在Java 8中,这一点甚至更简单:EDCOX1(4)我也建议重写toStrug()(使用构造函数传递),而不是使用名称,特别是如果枚举与可序列化数据关联,这样就可以在不给声纳匹配的情况下控制外壳。
Java 8当然能够/将在这个论坛上改变很多(更好的)答案。但不确定是否有尾巴(声纳)摇狗(应用程序代码)。
如果你想把它放在一个unmodifiableMap中,那么从一个ConcurrentHashMap开始是没有好处的。只需使用HashMap。(如果你有番石榴的ImmutableMap,那么我建议你用它代替!)
谷歌的IfMaMabLAP当然是一个更好的(真正的不可改变的)实现,但是为了演示一个唯一的核心Java解决方案…并且关注字符串映射查找案例,只使用核心Java类。总的来说,已经发现,考虑到总体性能(添加、删除、修改)和简单性,当必须考虑并发修改时,ConcurrentHashMap几乎总是优于HashMap。
静态初始化本质上是同步的,因此绝对没有理由在这里使用ConcurrentHashMap,在这里,初始化之后映射永远不会被修改。因此,为什么即使是JLS本身的示例也使用常规的HashMap。
代码中的注释显式地说明"任何map impl都可以做到"。对于初级开发人员来说,使用Concurrenthashmap作为一种常见的实践,在一般情况下不同步映射修改时,最好与常见的bug源进行权衡。
@如果我们处于多线程环境中,那么必须考虑选择的后果。在没有思想的情况下对同步集合的防御性使用与我们最初拥有并发性的原因背道而驰。我不明白为什么原则上应该是不变集合的集合可以从作为并发集合实现中获益。
@yoyo-同样,如前所述,任何映射impl都将执行,并且对于给定的impl确实没有任何结果,无论是正的还是负的。请阅读关于初级开发人员的先前评论,这样,考虑到Concurrenthashmap没有读取性能惩罚,所有的事情都具有通用映射impl的适用性,通常超过了hashmap,开发人员在更新期间必须非常仔细地考虑同步。因此,在使用Concurrenthashmap时可能不会产生任何后果,在需要同步的其他情况下也可能需要,这似乎是完全合理的。
如果这是您的坚定信念,那么我还建议使用synchronized (map) { ENUM_MAP = Collections.unmodifiableMap(map); },以避免在构建不可修改版本的方法内部使用可能的迭代器时出现不确定的行为-作为一个标准,这样初级开发人员就不必考虑这些相同的后果。请参见同步包装。
感谢@yoyo,这在上下文中是一个很好的impl片段,让其他人理解在构造/更新映射时访问迭代器的含义——这是一个微妙且难以调试的案例。
这里有一个方法可以对任何枚举执行此操作,并且不区分大小写。
/**
* Finds the value of the given enumeration by name, case-insensitive.
* Throws an IllegalArgumentException if no match is found.
**/
public static > T valueOfIgnoreCase(
Class 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
就像案件不敏感,但是…对于键和…对于这样一个可能具有代表性的查找,较小但迭代的性能较低。因此Enummap等人
这不管用!为了我的目的,我把equalsignorecase改成equals。尽管equals的两个输入完全相同,但代码失败。
使用Blah.valueOf(string)是最好的,但也可以使用Enum.valueOf(Blah.class, string)。
区分大小写,不起作用!
@你能澄清你的评论吗?你想做什么?
您好@peterlawrey,我正准备从字符串public enum objecttype person("person")public string parametername;objecttype(string parametername)this.parametername=parametername;public string getparametername()返回this.parametername;public static objecttype from string(string parametername)if(参数名称!=null)for(objectType objType:objectType.values())if(parametername.equalSignoreCase(objType.parametername))返回objType;返回null;
如果您不想编写自己的实用程序,请使用谷歌的guava库:
Enums.getIfPresent(Blah.class,"A")
与内置的Java函数不同,它让我们检查是否存在BLAH,并且不会抛出异常。
遗憾的是,它返回了谷歌可选的,而不是Java可选的。
真的。但被切除了。谷歌和Netflix有很棒的Java lib。在与Java追加类重叠的情况下,以新版本实现的类不可避免地会带来麻烦。必须全部在一个供应商库中。
这里我的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));
}
}
**编辑**
将函数改名为EDCOX1×4,因为使用该约定命名它,您将从Java语言本身获得一些好处;例如:
在HeaderParam注释处直接转换类型
或者,为了使您能够编写更可读的switch块,您可以使用.orElse(null)而不是.orElseThrow()来编写default子句中的异常抛出代码,并在需要时包含更有用的信息。为了更宽泛些,你可以使用v -> Objects.equals(v.name, s == null ?"" : s.trim().toUpperCase())。
或者从findFirst()返回Optional,让用户决定是否需要.orElse(null)、orElseThrow()或其他什么……
声明public static MyEnum valueOf(String)实际上是一个编译错误,因为它与隐式定义的相同,所以旧版本的答案实际上更好。(JLS,IDENON)
在Java 8或更高版本中,使用流:
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 fromText(String text) {
return Arrays.stream(values())
.filter(bl -> bl.text.equalsIgnoreCase(text))
.findFirst()
.orElse(null);
}
}
您可能需要这样做:
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"。
另一种方法是使用枚举的隐式静态方法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
灵感:Java中枚举的10个例子
这基本上就是valueOf为您所做的。这个静态方法不提供任何额外的,异常等等。那么if/else结构是非常危险的…添加的任何新枚举常量都将导致此方法在不更改的情况下中断。
还请考虑下面这个示例:我们如何使用valueof进行不区分大小写的查找,或者我们如何避免它的异常,并使用别名提供可选名称:stackoverflow.com/a/12659023/744133
name()不是静态的。
使用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 possible = Enums.getIfPresent(Planet.class, val);
if (!possible.isPresent()) {
throw new IllegalArgumentException(val +"? There is no such planet!");
}
return possible.get();
}
}
为了增加前面的答案,并解决一些关于空值和NPE的讨论,我使用了guava选项来处理缺席/无效的案例。这对于URI/参数解析非常有用。
public enum E {
A,B,C;
public static Optional 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/usingandvoidingnullExplained可选
在Java 8中,静态映射模式更容易,是我的预处理方法。如果要将枚举与Jackson一起使用,可以重写toString并使用它而不是名称,然后使用@JsonValue进行注释。
public enum MyEnum {
BAR,
BAZ;
private static final Map 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 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);
}
}
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
这或多或少与乔斯&233;米的答案相同。
o(1)方法的灵感来源于节俭的代码,该代码使用哈希图。
public enum USER {
STUDENT("jon",0),TEACHER("tom",1);
private static final Map 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的commons lang库有一个静态函数org.apache.commons.lang3.enumutils.getenum,它将字符串映射到枚举类型。基本上和杰弗里斯的答案一样,但为什么当它已经在野外的时候,还要自己滚呢?
添加到最热门的答案,有一个有用的实用程序…
valueOf()在不喜欢其输入的情况下抛出两个不同的异常。
IllegalArgumentException
NullPointerExeption
如果您的要求是这样的,您没有任何保证您的字符串一定会匹配枚举值,例如,如果字符串数据来自数据库并且可能包含枚举的旧版本,那么您需要经常处理这些…
所以这里有一个我编写的可重用方法,它允许我们定义一个默认的枚举,如果我们传递的字符串不匹配,它将被返回。
private static > 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
}
EDCOX1 22定义了几种有用的方法,这些方法对于Java中的所有枚举类型都是可用的:
可以使用name()方法获取任何枚举常量的名称。用于写入枚举常量的字符串文字是它们的名称。
同样,可以使用values()方法从枚举类型中获取所有枚举常量的数组。
对于被问及的问题,如图所示,可以使用EDCOX1×5的方法将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
在这段代码中,valueOf()方法返回一个枚举常量gender.male,调用它的名称返回"MALE"。
怎么样?
public enum MyEnum {
FIRST,
SECOND,
THIRD;
public static Optional fromString(String value){
try{
return Optional.of(MyEnum.valueOf(value));
}catch(Exception e){
return Optional.empty();
}
}
}
以相反的方式捕获另一个实用程序。使用标识该枚举的值,而不是其名称。
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.EnumSet;
public class EnumUtil {
/**
* Returns the Enum of type enumType whose a
* public method return value of this Enum is
* equal to valor.
* 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 from(Class enumType, Object value) {
String methodName = getMethodIdentifier(enumType);
return from(enumType, value, methodName);
}
/**
* Returns the Enum of type enumType whose
* public method methodName return is
* equal to value.
*
* @param enumType
* @param value
* @param methodName
* @return
*/
public static > E from(Class enumType, Object value, String methodName) {
EnumSet 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有超过public、非final、非static的方法,例如返回"drei"的getTranslate,则可以使用另一种方法:EnumUtil.from(Foo.class,"drei","getTranslate")。
由于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)的合同,而不以不返还null的方式抛出IllegalArgumentException。因此,如果名称为null,我们抛出NullPointerException;如果名称为default,我们抛出NullPointerException;如果名称为defaultValue,我们抛出null。这就是valueOfOrDefault的工作原理。
该方法采用EDCOX1×17接口的设计,提供了Java 8的EDOCX1×18的方法。
获取枚举名称的最快方法是在应用程序启动时创建枚举文本和值的映射,并获取名称调用函数blah.getEnumName():
public enum Blah {
A("text1"),
B("text2"),
C("text3"),
D("text4");
private String text;
private HashMap map;
Blah(String text) {
this.text = text;
}
public String getText() {
return this.text;
}
static{
createMapOfTextAndName();
}
public static void createMapOfTextAndName() {
map = new HashMap();
for (Blah b : Blah.values()) {
map.put(b.getText(),b.toString());
}
}
public static String getEnumName(String text) {
return map.get(text.toLowerCase());
}
}
我喜欢使用这种过程将命令作为字符串解析为枚举。我通常将其中一个枚举设置为"未知",因此在未找到其他枚举时返回(即使是在不区分大小写的基础上),而不是空枚举(这意味着没有值)会有所帮助。因此我使用这种方法。
static > Enum getEnumValue(String what, Class enumClass) {
Enum unknown=null;
for (Enum enumVal: enumClass.getEnumConstants()) {
if (what.compareToIgnoreCase(enumVal.name()) == 0) {
return enumVal;
}
if (enumVal.name().compareToIgnoreCase("unknown") == 0) {
unknown=enumVal;
}
}
return unknown;
}
看起来不错,但基本上和帕特里克·阿内森的答案一样…