Risposte:
Sì, Blah.valueOf("A")
ti darà Blah.A
.
Nota che il nome deve corrispondere esattamente , incluso case: Blah.valueOf("a")
ed Blah.valueOf("A ")
entrambi lanciano unIllegalArgumentException
.
I metodi statici valueOf()
e values()
vengono creati in fase di compilazione e non vengono visualizzati nel codice sorgente. Tuttavia, appaiono in Javadoc; ad esempio, Dialog.ModalityType
mostra entrambi i metodi.
toString()
valore, no, non lo direi. name()
ti darà il nome effettivo definito della costante enum a meno che tu non lo ignori.
enum Blah {...}
definizione effettiva non dovrebbe cercare di dichiarare values
né propria valuesOf
. È come scrivere "AnyTypeName.class" anche se in realtà non hai mai dichiarato una variabile membro "class"; il compilatore rende tutto Just Work. (Questa risposta potrebbe non esserti più utile 3 mesi dopo, ma per ogni evenienza.)
Un'altra soluzione se il testo non è uguale al valore di enumerazione:
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")
sarebbe meglio di return null
.
Ecco una bella utility che 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;
}
Quindi nella mia classe enum di solito ho questo per salvare un po 'di battitura:
public static MyEnum fromString(String name) {
return getEnumFromString(MyEnum.class, name);
}
Se le tue enumerazioni non sono tutte maiuscole, basta cambiare il Enum.valueOf
linea.
Peccato che non posso usare T.class
per Enum.valueOf
come T
è cancellato.
Usa lo schema di Joshua Bloch, Effective Java :
(semplificato per brevità)
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);
}
}
Vedi anche:
Oracle Java Esempio usando Enum e Mappa delle istanze
Stream.of(MyEnum.values()).collect(toMap(Enum::name, identity()))
ti consiglio anche di sovrascrivere toString () (passato attraverso il costruttore) e di usarlo al posto del nome, specialmente se l'Enum è associato a dati serializzabili in quanto ti consente di controllare il case senza dare Sonar adatto.
unmodifiableMap
comunque in, non c'è alcun vantaggio nell'iniziare con un ConcurrentHashMap
. Basta usare a HashMap
. (Se hai Guava, ImmutableMap
lo consiglierei invece!)
ConcurrentHashMap
qui, dove la mappa non viene mai modificata dopo l'inizializzazione. Ecco perché anche ad esempio l'esempio nella stessa JLS usa un regolare HashMap
.
Dovresti anche stare attento con il tuo caso. Lasciami spiegare: fare Blah.valueOf("A")
lavori, ma Blah.valueOf("a")
non funzionerà. Poi di nuovoBlah.valueOf("a".toUpperCase(Locale.ENGLISH))
avrebbe funzionato.
modifica
Modificato in toUpperCase
in toUpperCase(Locale.ENGLISH)
base a tc. commento e documenti java
edit2
Su Android dovresti usare Locale.US
, come sottolinea Sulai .
Locale.US
input / output leggibili dalla macchina.
Ecco un metodo che può farlo per qualsiasi Enum ed è case sensitive.
/**
* 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
è la strada da percorrere. +1
Usare Blah.valueOf(string)
è il migliore ma puoi anche usarlo Enum.valueOf(Blah.class, string)
.
In Java 8 o versioni successive, utilizzando 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 non vuoi scrivere la tua utility, usa Google guaiava biblioteca:
Enums.getIfPresent(Blah.class, "A")
A differenza della funzione Java integrata, ti consente di verificare se A è presente in Blah e non genera un'eccezione.
I miei 2 centesimi qui: usando Java8 Streams + controllando una stringa esatta:
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));
}
}
** MODIFICARE **
Rinominata la funzione da fromString()
quando la ha denominata usando quella convenzione, otterrai alcuni vantaggi dal linguaggio Java stesso; per esempio:
switch
blocchi più leggibili , è possibile .orElse(null)
invece .orElseThrow()
che sia possibile codificare il lancio dell'eccezione nella default
clausola e includere ulteriori informazioni utili quando richiesto. E per renderlo più indulgente potresti usarev -> Objects.equals(v.name, s == null ? "" : s.trim().toUpperCase())
Optional
da findFirst()
, consentendo all'utente di decidere se vuole .orElse(null)
, orElseThrow()
o altro ....
Potrebbe essere necessario questo:
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;
}
}
Un'altra aggiunta:
public static String fromEnumName(String parameterName) {
if (parameterName != null) {
for (DQJ objType : DQJ.values()) {
if (parameterName.equalsIgnoreCase(objType.name())) {
return objType.parameterName;
}
}
}
return null;
}
Questo ti restituirà il valore con un nome Enum rigoroso Ad esempio, se fornisci "PERSON" nel fromEnumName, ti restituirà il valore di Enum, ovvero "Person"
Un altro modo per farlo utilizzando il metodo statico implicito name()
di Enum. name restituirà la stringa esatta utilizzata per creare quell'enum che può essere utilizzato per verificare la stringa fornita:
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");
}
}
test:
System.out.println(Blah.getEnum("B").name());
//it will print B B
ispirazione: 10 esempi di Enum in Java
valueOf
fa per te. Questo metodo statico non offre nulla in più, ad eccezione di tutti. Quindi i costrutti if / else sono altamente pericolosi ... qualsiasi nuova costante enum aggiunta causerà la rottura di questo metodo senza modifiche.
name()
non è statico.
Soluzione che utilizza librerie Guava. Il metodo getPlanet () non fa distinzione tra maiuscole e minuscole, quindi getPlanet ("MerCUrY") restituirà 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();
}
}
Per aggiungere alle risposte precedenti e affrontare alcune delle discussioni su null e NPE sto usando Guava Optionals per gestire casi assenti / non validi. Funziona benissimo per l'analisi URI / parametri.
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();
}
}
}
Per coloro che non ne sono a conoscenza, ecco alcune informazioni su come evitare null con Opzionale: https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional
In Java 8 il modello di mappa statica è ancora più semplice ed è il mio metodo preferito. Se si desidera utilizzare l'Enum con Jackson, è possibile eseguire l'override di String e utilizzarlo al posto del nome, quindi annotare con@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) metodo ispirato al codice generato dall'usato che utilizza una 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;
}
}
Enum è molto utile, ho usato Enum
molto per aggiungere una descrizione per alcuni campi in diverse lingue, come nell'esempio seguente:
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;
}
}
Quindi puoi recuperare la descrizione in modo dinamico in base al codice della lingua passato al getDescription(String lang)
metodo, ad esempio:
String statusDescription = Status.valueOf("ACT").getDescription("en");
java.lang.Enum
definisce diversi metodi utili, disponibili per tutti i tipi di enumerazione in Java:
name()
metodo per ottenere il nome di qualsiasi costante Enum. Il letterale stringa usato per scrivere costanti di enum è il loro nome.values()
metodo può essere usato per ottenere una matrice di tutte le costanti Enum da un tipo Enum.valueOf()
metodo per convertire qualsiasi stringa in costante Enum in Java, come mostrato di seguito.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
In questo frammento di codice, il valueOf()
metodo restituisce una costante Enum Gender.MALE, chiamando il nome su quel ritorno "MALE"
.
La libreria commons-lang di Apache ha una funzione statica org.apache.commons.lang3.EnumUtils.getEnum che mapperà una stringa sul tuo tipo Enum. Stessa risposta essenzialmente di Geoffreys, ma perché farlo da solo quando è già in circolazione.
Aggiungendo alla risposta più votata, con un'utilità utile ...
valueOf()
genera due diverse eccezioni nei casi in cui non gli piace il suo input.
IllegalArgumentException
NullPointerExeption
Se i tuoi requisiti sono tali da non avere alcuna garanzia che la tua stringa corrisponderà sicuramente a un valore enum, ad esempio se i dati String provengono da un database e potrebbero contenere una versione precedente dell'enum, allora dovrai gestirli spesso...
Quindi ecco un metodo riutilizzabile che ho scritto che ci consente di definire un Enum predefinito da restituire se la stringa che passiamo non corrisponde.
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;
}
}
Usalo in questo modo:
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
}
Dato che una switch
versione non è stata ancora menzionata, la presento (riutilizzando l'enum del PO):
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);
}
}
}
Dal momento che questo non dà alcun valore aggiuntivo al valueOf(String name)
metodo, ha senso definire un metodo aggiuntivo solo se vogliamo avere un comportamento diverso. Se non vogliamo sollevare un IllegalArgumentException
, possiamo cambiare l'implementazione in:
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;
}
}
}
Fornendo un valore predefinito manteniamo il contratto di Enum.valueOf(String name)
senza gettare un IllegalArgumentException
in quel modo che in nessun caso null
viene restituita. Pertanto lanciamo a NullPointerException
se il nome è null
e in caso di default
se lo defaultValue
è null
. valueOfOrDefault
Funziona così .
Questo approccio adotta il design di Map
-Interface che fornisce un metodo a Map.getOrDefault(Object key, V defaultValue)
partire da Java 8.
Un'altra utilità catturare in modo inverso. Utilizzando un valore che identifica quell'Enum, non dal suo 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;
}
}
Esempio:
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")
ritorna Foo.THREE
, perché utilizzerà getValue
per abbinare "drei", che è un metodo pubblico unico, non definitivo e non statico in Foo. Nel caso Foo ha più il metodo pubblico, non definitivo e non statica, ad esempio, getTranslate
che restituisce "drei", l'altro metodo può essere utilizzato: EnumUtil.from(Foo.class, "drei", "getTranslate")
.
Creare un interno e quindi chiamare valueOf<MyEnum>("value")
. Se il tipo non è valido, otterrai null e dovrai gestirlo
inline fun <reified T : Enum<T>> valueOf(type: String): T? {
return try {
java.lang.Enum.valueOf(T::class.java, type)
} catch (e: Exception) {
null
}
}
In alternativa, è possibile impostare un valore predefinito, chiamando valueOf<MyEnum>("value", MyEnum.FALLBACK)
ed evitando una risposta nulla. Puoi estendere il tuo enum specifico per rendere automatico il default
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
}
}
O se vuoi entrambi, fai il secondo:
inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T = valueOf<T>(type) ?: default
Mi piace usare questo tipo di processo per analizzare i comandi come stringhe in enumerazioni. Normalmente ho una delle enumerazioni come "sconosciuta", quindi aiuta a far sì che venga restituita quando le altre non vengono trovate (anche su una base insensibile al maiuscolo / minuscolo) piuttosto che nulla (questo significa che non ha valore). Quindi uso questo approccio.
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;
}
Il modo più rapido per ottenere il nome di enum è creare una mappa del testo e del valore di enum all'avvio dell'applicazione e ottenere il nome chiamando la funzione 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")
metodo fa distinzione tra maiuscole e minuscole e non tollera spazi bianchi estranei, quindi la soluzione alternativa proposta di seguito da @ JoséMi.