Respostas:
Sim, Blah.valueOf("A")
vou te dar Blah.A
.
Observe que o nome deve ser uma correspondência exata , incluindo maiúsculas Blah.valueOf("a")
e minúsculas: e Blah.valueOf("A ")
ambos jogam um IllegalArgumentException
.
Os métodos estáticos valueOf()
e values()
são criados no momento da compilação e não aparecem no código-fonte. Eles aparecem no Javadoc; por exemplo, Dialog.ModalityType
mostra os dois métodos.
toString()
valor, não, eu não diria isso. name()
obterá o nome definido real da constante enum, a menos que você o substitua.
enum Blah {...}
definição real não deve tentar declarar a sua própria values
nem valuesOf
. É como você pode escrever "AnyTypeName.class" mesmo que nunca tenha declarado uma variável de membro "class"; o compilador faz tudo funcionar. (Esta resposta não pode ser útil para você 3 meses mais tarde, mas apenas no caso.)
Outra solução se o texto não for igual ao valor da enumeração:
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")
seria melhor que return null
.
Aqui está um utilitário bacana que eu uso:
/**
* 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;
}
Então, na minha classe enum, geralmente tenho isso para salvar algumas digitações:
public static MyEnum fromString(String name) {
return getEnumFromString(MyEnum.class, name);
}
Se suas enumerações não são todas maiúsculas, basta alterar a Enum.valueOf
linha.
Pena que eu não posso usar T.class
para Enum.valueOf
como T
é apagada.
Use o padrão de Joshua Bloch, Java Efetivo :
(simplificado por questões de brevidade)
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);
}
}
Veja também:
Exemplo de Oracle Oracle usando Enum e mapa de instâncias
Ordem de execução de blocos estáticos em um tipo Enum
Como posso procurar uma enumeração Java a partir do seu valor String
Stream.of(MyEnum.values()).collect(toMap(Enum::name, identity()))
eu também recomendo substituir toString () (transmitido pelo construtor) e usá-lo em vez de nome, especialmente se o Enum estiver associado a dados serializáveis, pois isso permite controlar a caixa sem fornecer Sonar um ajuste.
unmodifiableMap
qualquer maneira, não há nenhum benefício em começar com a ConcurrentHashMap
. Basta usar um HashMap
. (Se você tiver Goiaba do ImmutableMap
então eu recomendo que em vez!)
ConcurrentHashMap
aqui, onde o mapa nunca é modificado após a inicialização. Por isso, mesmo que, por exemplo, o exemplo no próprio JLS use um regular HashMap
.
Você também deve ter cuidado com o seu caso. Deixe-me explicar: fazer Blah.valueOf("A")
obras, mas Blah.valueOf("a")
não vai funcionar. Então, novamente Blah.valueOf("a".toUpperCase(Locale.ENGLISH))
funcionaria.
editar
Alterado toUpperCase
para com toUpperCase(Locale.ENGLISH)
base em tc. comentar e os documentos java
edit2
No Android, você deve usar Locale.US
, como sulai aponta .
Locale.US
entradas / saídas legíveis por máquina.
Aqui está um método que pode fazer isso para qualquer Enum e não diferencia maiúsculas de minúsculas.
/**
* 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()
));
}
equalsIgnoreCase
é o caminho a percorrer. +1
Usar Blah.valueOf(string)
é melhor, mas você também pode usá-lo Enum.valueOf(Blah.class, string)
.
No Java 8 ou posterior, usando o 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();
}
}
Se você não quiser escrever seu próprio utilitário, use o goiaba biblioteca:
Enums.getIfPresent(Blah.class, "A")
Ao contrário da função java incorporada, vamos verificar se A está presente em Blah e não gera uma exceção.
Meus 2 centavos aqui: usando Java8 Streams + verificando uma string exata:
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));
}
}
** EDIT **
Renomeada a função para que, fromString()
desde o nome da convenção, você obtenha alguns benefícios da própria linguagem Java; por exemplo:
switch
blocos mais legíveis , é possível, em .orElse(null)
vez de .orElseThrow()
codificar a exceção - na default
cláusula - e incluir informações mais úteis quando necessário. E para torná-lo mais branda você poderia usarv -> Objects.equals(v.name, s == null ? "" : s.trim().toUpperCase())
Optional
partir findFirst()
, permitindo ao usuário decidir se quer .orElse(null)
, orElseThrow()
ou o que quer ....
public static MyEnum valueOf(String)
é realmente um erro de compilação, já que é o mesmo que o definido implicitamente, portanto, a versão mais antiga da sua resposta é realmente melhor. ( jls , ideone )
Você pode precisar disso:
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;
}
}
Mais uma adição:
public static String fromEnumName(String parameterName) {
if (parameterName != null) {
for (DQJ objType : DQJ.values()) {
if (parameterName.equalsIgnoreCase(objType.name())) {
return objType.parameterName;
}
}
}
return null;
}
Isso retornará o valor por um nome de enum com string. Por exemplo, se você fornecer "PERSON" no fromEnumName, ele retornará o valor de enum, ou seja, "Person"
Outra maneira de fazer isso usando o método estático implícito name()
do Enum. name retornará a string exata usada para criar a enumeração que pode ser usada para verificar a string fornecida:
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");
}
}
Teste:
System.out.println(Blah.getEnum("B").name());
//it will print B B
inspiration: 10 exemplos de enum em Java
valueOf
faz para você. Este método estático não oferece nada extra, exceção e tudo. Então as construções if / else são altamente perigosas ... qualquer nova constante de enum adicionada fará com que esse método seja interrompido sem alterações.
name()
não é estático.
Solução usando bibliotecas Guava. O método getPlanet () não faz distinção entre maiúsculas e minúsculas; portanto, getPlanet ("MerCUrY") retornará 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();
}
}
Para adicionar às respostas anteriores e abordar algumas das discussões sobre nulos e NPE, estou usando Guava Optionals para lidar com casos ausentes / inválidos. Isso funciona muito bem para análise de URI / parâmetro.
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();
}
}
}
Para quem não está ciente, veja mais algumas informações sobre como evitar nulo com Opcional: https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional
No Java 8, o padrão estático do Mapa é ainda mais fácil e é o meu método preferido. Se você deseja usar o Enum com Jackson, você pode substituir ToString e usá-lo em vez de nome, e anotar com@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);
}
}
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;
}
O (1) método inspirado em códigos gerados em parcelas que utilizam um mapa hash.
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;
}
}
Enum é muito útil, tenho usado Enum
muito para adicionar uma descrição para alguns campos em diferentes idiomas, como no exemplo a seguir:
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;
}
}
E então você pode recuperar a descrição dinamicamente com base no código do idioma passado ao getDescription(String lang)
método, por exemplo:
String statusDescription = Status.valueOf("ACT").getDescription("en");
java.lang.Enum
define vários métodos úteis, que estão disponíveis para todos os tipos de enumeração em Java:
name()
método para obter o nome de quaisquer constantes Enum. O literal de string usado para escrever constantes enum é o nome deles.values()
método pode ser usado para obter uma matriz de todas as constantes Enum de um tipo Enum.valueOf()
método para converter qualquer constante String para Enum em Java, como mostrado abaixo.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
Nesse trecho de código, o valueOf()
método retorna uma constante Enum Gender.MALE, chamando o nome nesse retorno "MALE"
.
A biblioteca commons-lang do Apache possui uma função estática org.apache.commons.lang3.EnumUtils.getEnum, que mapeará uma String para o seu tipo de Enum. A mesma resposta, essencialmente, como Geoffreys, mas por que rolar a sua própria quando já está lá fora?
Adicionando à resposta mais votada, com um utilitário útil ...
valueOf()
lança duas exceções diferentes nos casos em que não gosta de sua entrada.
IllegalArgumentException
NullPointerExeption
Se seus requisitos forem tais que você não tenha garantia de que sua String definitivamente corresponderá a um valor de enum, por exemplo, se os dados da String vierem de um banco de dados e puderem conter uma versão antiga da enum, será necessário lidar com eles frequentemente...
Então, aqui está um método reutilizável que eu escrevi que permite definir um Enum padrão a ser retornado se a String que passarmos não corresponder.
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;
}
}
Use-o assim:
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
}
Como uma switch
versão-ainda não foi mencionada, eu a apresento (reutilizando a enumeração do 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);
}
}
}
Como isso não dá nenhum valor adicional ao valueOf(String name)
método, faz sentido definir um método adicional se quisermos ter um comportamento diferente. Se não queremos levantar umIllegalArgumentException
, podemos alterar a implementação para:
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;
}
}
}
Ao fornecer um valor padrão que manter o contrato de Enum.valueOf(String name)
sem lançar uma IllegalArgumentException
dessa maneira que em nenhum caso null
é devolvido. Portanto, lançamos um NullPointerException
se o nome é null
e, no caso de, default
se defaultValue
énull
. É assim que valueOfOrDefault
funciona.
Essa abordagem adota o design da Map
interface - que fornece um método a Map.getOrDefault(Object key, V defaultValue)
partir do Java 8.
Outro utilitário capturando de maneira inversa. Usando um valor que identifique esse Enum, não pelo nome.
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;
}
}
Exemplo:
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")
retorna Foo.THREE
, porque será usado getValue
para corresponder ao "drei", que é um método público único, não final e não estático no Foo. No caso Foo tem mais do que na método público, não é final e não estática, por exemplo, getTranslate
que retorna "Drei", o outro método pode ser usado: EnumUtil.from(Foo.class, "drei", "getTranslate")
.
Crie um ramal e ligue valueOf<MyEnum>("value")
. Se o tipo for inválido, você será nulo e precisará lidar com isso
inline fun <reified T : Enum<T>> valueOf(type: String): T? {
return try {
java.lang.Enum.valueOf(T::class.java, type)
} catch (e: Exception) {
null
}
}
Como alternativa, você pode definir um valor padrão, chamando valueOf<MyEnum>("value", MyEnum.FALLBACK)
e evitando uma resposta nula. Você pode estender sua enum específica para que o padrão seja automático
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
}
}
Ou, se você quiser os dois, faça o segundo:
inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T = valueOf<T>(type) ?: default
Eu gosto de usar esse tipo de processo para analisar comandos como seqüências de caracteres em enumerações. Normalmente, eu tenho uma das enumerações como "desconhecida", portanto, isso ajuda a retornar quando as outras não são encontradas (mesmo que não sejam sensíveis a maiúsculas e minúsculas) em vez de nulas (o que significa que não há valor). Portanto, eu uso essa abordagem.
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;
}
A maneira mais rápida de obter o nome de enum é criar um mapa de texto e valor de enum quando o aplicativo é iniciado e, para obter o nome, chame a função 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());
}
}
Blah.valueOf("A")
método diferencia maiúsculas de minúsculas e não tolera espaços em branco estranhos, portanto, a solução alternativa proposta abaixo por @ JoséMi.