typed - status enum java




Como obter um valor enum de um valor de string em Java? (16)

A biblioteca commons-lang do Apache possui uma função estática org.apache.commons.lang3.EnumUtils.getEnum que org.apache.commons.lang3.EnumUtils.getEnum uma String para o seu tipo Enum. A mesma resposta, essencialmente, como Geoffreys, mas por que lançar o seu próprio quando está lá fora na natureza já.

Digamos que eu tenha um enum que é apenas

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

e gostaria de encontrar o valor enum de uma string, por exemplo "A" que seria Blah.A Como seria possível fazer isso?

É o Enum.valueOf() o método que eu preciso? Se sim, como eu usaria isso?


Adicionando à resposta mais bem cotada, 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 os seus requisitos são tais que você não tem garantia de que sua String irá definitivamente corresponder a um valor de enum, por exemplo, se os dados de String vierem de um banco de dados e puderem conter uma versão antiga do enum, frequentemente...

Então aqui está um método reutilizável que eu escrevi que nos permite definir um Enum padrão para ser retornado se a String que nós passamos 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 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
}

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 eu tenho isso para salvar algumas digitações:

public static MyEnum fromString(String name) {
    return getEnumFromString(MyEnum.class, name);
}

Se suas enums não estiverem todas em maiúsculas, apenas altere a linha Enum.valueOf .

Pena que não posso usar o T.class para Enum.valueOf quando T é apagado.


Como um switch -version ainda não foi mencionado, eu o introduzo (reutilizando o enum 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 fornece nenhum valor adicional ao método valueOf(String name) , só faz sentido definir um método adicional se quisermos ter um comportamento diferente. Se não quisermos criar um IllegalArgumentException , 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, mantemos o contract de Enum.valueOf(String name) sem lançar um IllegalArgumentException dessa maneira que, em nenhum caso, será retornado como null . Portanto, lançamos um NullPointerException se o nome for null e, no caso de default se defaultValue for null . É assim que funciona o valueOfOrDefault .

Essa abordagem adota o design da Map.getOrDefault(Object key, V defaultValue) de Map que fornece um método Map.getOrDefault(Object key, V defaultValue) partir do Java 8.


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

** EDITAR **

Renomeado a função para fromString() desde sua nomeação usando essa convenção, você obterá alguns benefícios da própria linguagem Java; por exemplo:

  1. Conversão direta de tipos na anotação HeaderParam

No Java 8 ou posterior, usando 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 Blah fromText(String text) {
        return Arrays.stream(values())
          .filter(bl -> bl.text.equalsIgnoreCase(text))
          .findFirst()
          .orElse(null);
    }
}

O (1) método inspirado no código gerado pelo thrift que utiliza um hashmap.

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

}

Outra maneira de fazer isso usando o método estático implícito name() do Enum. name retornará a string exata usada para criar o enum que pode ser usado 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

Inspiração: 10 Exemplos de Enum em Java


Outra utilidade que captura de maneira inversa. Usando um valor que identifique esse Enum, não de seu 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 ele usará getValue para corresponder a "drei", que é um método público, não final e não estático em Foo. Caso o Foo tenha mais do que um método público, não final e não estático, por exemplo, getTranslate que retorna "drei", o outro método pode ser usado: EnumUtil.from(Foo.class, "drei", "getTranslate") .


Para adicionar as respostas anteriores e abordar algumas das discussões sobre nulos e NPE, estou usando o Guava Optionals para manipular casos ausentes / inválidos. Isso funciona muito bem para a análise de parâmetros / 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();
        }
    }
}

Para aqueles que não sabem, veja mais algumas informações sobre como evitar nulos com o Opcional: https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional


Sim, Blah.valueOf("A") lhe dará Blah.A

Observe que o nome deve ser uma correspondência exata , incluindo maiúsculas e minúsculas: Blah.valueOf("a") e Blah.valueOf("A ") lançam um IllegalArgumentException .

Os métodos estáticos valueOf() e values() são criados em tempo de compilação e não aparecem no código-fonte. Eles aparecem em Javadoc, no entanto; por exemplo, Dialog.ModalityType mostra os dois métodos.


Sobre o quê?

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

Usar Blah.valueOf(string) é melhor, mas você também pode usar Enum.valueOf(Blah.class, string) .


Use o padrão de Joshua Bloch, Java efetivo :

(simplificado por 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 Java usando Enum e Mapa de instâncias

Ordem de execução de blocos estáticos em um tipo Enum

Como posso procurar um enum Java a partir de seu valor String


Você também deve ter cuidado com o seu caso. Deixe-me explicar: fazer Blah.valueOf("A") funciona, mas Blah.valueOf("a") não funcionará. Então, novamente Blah.valueOf("a".toUpperCase(Locale.ENGLISH)) funcionaria.

editar
Alterado toUpperCase para toUpperCase(Locale.ENGLISH) baseado em tc. comentar e os docs java

No android, você deve usar o Locale.US , como indica o sulai .


java.lang.Enum define vários métodos úteis, que estão disponíveis para todos os tipos de enumeração em Java:

  • Você pode usar o método name() para obter o nome de qualquer constante Enum. O literal de string usado para gravar constantes de enum é seu nome.
  • De forma semelhante values() método values() pode ser usado para obter uma matriz de todas as constantes Enum de um tipo Enum.
  • E para a pergunta feita, você pode usar o método valueOf() para converter qualquer string para a constante 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

Neste trecho de código, o método valueOf() retorna uma constante Enum Gender.MALE, chamando o nome que retorna "MALE" .





enums