recorrer - que es un enum en java
¿Cómo obtener un valor de enumeración de un valor de cadena en Java? (24)
Digamos que tengo un enum que es justo
public enum Blah {
A, B, C, D
}
y me gustaría encontrar el valor de enumeración de una cadena, por ejemplo "A"
que sería Blah.A
¿Cómo sería posible hacer esto?
¿Es el Enum.valueOf()
el método que necesito? Si es así, ¿cómo usaría esto?
¿Qué pasa?
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();
}
}
}
Agregando a la respuesta mejor calificada, con una utilidad útil ...
valueOf()
lanza dos excepciones diferentes en los casos en que no le gusta su entrada.
-
IllegalArgumentException
-
NullPointerExeption
Si sus requisitos son tales que no tiene ninguna garantía de que su Cadena encajará definitivamente con un valor de enumeración, por ejemplo, si los datos de Cadena provienen de una base de datos y podrían contener una versión antigua de la enumeración, entonces deberá manejar estos a menudo...
Así que aquí hay un método reutilizable que escribí que nos permite definir un Enum predeterminado que se devolverá si la cadena que pasamos no coincide.
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;
}
}
Úsalo así:
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
}
Aquí hay un método que puede hacerlo para cualquier Enum, y es insensible a mayúsculas y 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()
));
}
Aquí hay una utilidad ingeniosa que 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;
}
Luego, en mi clase de enumeración, generalmente tengo esto para guardar algo de escritura:
public static MyEnum fromString(String name) {
return getEnumFromString(MyEnum.class, name);
}
Si sus enumeraciones no son todas mayúsculas, solo cambie la línea Enum.valueOf
.
Lástima que no puedo usar T.class
para Enum.valueOf
ya que T
se borra.
Como no se ha mencionado aún una versión de switch
, la introduzco (reutilizando la enumeración de 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);
}
}
}
Ya que esto no le da ningún valor adicional al método valueOf(String name)
, solo tiene sentido definir un método adicional si queremos tener un comportamiento diferente. Si no queremos generar una IllegalArgumentException
, podemos cambiar la implementación a:
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;
}
}
}
Al proporcionar un valor predeterminado, mantenemos el contract de Enum.valueOf(String name)
sin lanzar una IllegalArgumentException
de esa manera que en ningún caso se devuelve null
. Por lo tanto, lanzamos una NullPointerException
si el nombre es null
y, en caso de que sea default
si defaultValue
es null
. Así es como funciona valueOfOrDefault
.
Este enfoque adopta el diseño del Map
-Interfaz que proporciona un método Map.getOrDefault(Object key, V defaultValue)
partir de Java 8.
El método O (1) está inspirado en el código generado por ahorro que utiliza un mapa de 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;
}
}
En Java 8 o posterior, utilizando 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);
}
}
En Java 8, el patrón de Mapa estático es aún más fácil y es mi método preferido. Si desea utilizar el Enum con Jackson, puede anular toString y usarlo en lugar del nombre, y luego anotar 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);
}
}
La biblioteca commons-lang Apache tiene una función estática org.apache.commons.lang3.EnumUtils.getEnum que asignará una cadena a su tipo Enum. Esencialmente, la misma respuesta que Geoffreys, pero ¿por qué rodar la tuya cuando ya está en libertad?
Me gusta usar este tipo de proceso para analizar comandos como cadenas en enumeraciones. Normalmente tengo una de las enumeraciones como "desconocida", por lo que es útil devolverla cuando no se encuentran las otras (incluso en una base que no distingue entre mayúsculas y minúsculas) en lugar de nula (lo que significa que no hay valor). Por eso utilizo este enfoque.
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;
}
Mis 2 centavos aquí: usando Java8 Streams + comprobando una cadena exacta:
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 **
Cambió el nombre de la función a fromString()
desde que la nombró usando esa convención, obtendrá algunos beneficios del lenguaje Java en sí; por ejemplo:
Otra forma de hacerlo es mediante el uso de un name()
método estático implícito name()
de Enum. nombre devolverá la cadena exacta utilizada para crear esa enumeración que se puede usar para verificar contra la cadena proporcionada:
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");
}
}
Pruebas:
System.out.println(Blah.getEnum("B").name());
//it will print B B
inspiración: 10 ejemplos de Enum en Java
Otra solución si el texto no es el mismo que el valor de enumeración:
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;
}
}
Otra utilidad de captura de manera inversa. Usando un valor que identifique ese Enum, no de su nombre.
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;
}
}
Ejemplo:
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")
devuelve Foo.THREE
, porque usará getValue
para coincidir con "drei", que es un método público único, no definitivo y no estático en Foo. En el caso de que Foo tenga más de un método público, no final y no estático, por ejemplo, getTranslate
que devuelve "drei", se puede usar el otro método: EnumUtil.from(Foo.class, "drei", "getTranslate")
.
Para agregar a las respuestas anteriores, y abordar algunas de las discusiones sobre nulos y NPE, estoy usando las opciones de guayaba para manejar los casos ausentes / no válidos. Esto funciona muy bien para URI / análisis de parámetros.
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 aquellos que no lo saben, aquí hay algo más de información sobre cómo evitar nulos con Opcional: https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional
Puede que necesites esto:
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;
}
}
Una adición más:
public static String fromEnumName(String parameterName) {
if (parameterName != null) {
for (DQJ objType : DQJ.values()) {
if (parameterName.equalsIgnoreCase(objType.name())) {
return objType.parameterName;
}
}
}
return null;
}
Esto le devolverá el valor por un nombre de Stringified Enum. Por ejemplo, si proporciona "PERSONA" en el fromEnumName, le devolverá el valor de Enum, es decir, "Persona"
Sí, Blah.valueOf("A")
te dará Blah.A
Tenga en cuenta que el nombre debe ser una coincidencia exacta , incluido el caso: Blah.valueOf("a")
y Blah.valueOf("A ")
ambos lanzan una IllegalArgumentException
.
Los métodos estáticos valueOf()
y values()
se crean en tiempo de compilación y no aparecen en el código fuente. Sin embargo, sí aparecen en Javadoc; por ejemplo, Dialog.ModalityType
muestra ambos métodos.
Si no desea escribir su propia utilidad, utilice la biblioteca de guava de Google:
Enums.getIfPresent(Blah.class, "A")
A diferencia de la función java incorporada, le permite verificar si A está presente en Blah y no lanza una excepción.
Solución utilizando bibliotecas de guayaba. El método getPlanet () no distingue entre mayúsculas y minúsculas, por lo que getPlanet ("MerCUrY") devolverá 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();
}
}
También debes tener cuidado con tu caso. Déjame explicarte: hacer Blah.valueOf("A")
funciona, pero Blah.valueOf("a")
no funciona. Luego, nuevamente Blah.valueOf("a".toUpperCase(Locale.ENGLISH))
funcionaría.
editar
Se cambió a toUpperCase(Locale.ENGLISH)
a toUpperCase(Locale.ENGLISH)
basado en tc. comentar y los documentos java
edit2 En Android debes usar Locale.US
, como señala sulai .
Usar Blah.valueOf(string)
es mejor, pero también puedes usar Enum.valueOf(Blah.class, string)
.
Utilice el patrón de Joshua Bloch, Java efectivo :
(simplificado por brevedad)
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);
}
}
Ver también:
Ejemplo de Oracle Java usando Enum y mapa de instancias
Orden de ejecución de bloques estáticos en un tipo Enum
¿Cómo puedo buscar una enumeración de Java desde su valor de cadena?
java.lang.Enum
define varios métodos útiles, que están disponibles para todos los tipos de enumeración en Java:
- Puede usar el método
name()
para obtener el nombre de las constantes de Enum. El literal de cadena utilizado para escribir constantes de enumeración es su nombre. - Similar método de
values()
se puede utilizar para obtener una matriz de todas las constantes Enum de un tipo Enum. - Y para la pregunta formulada, puede usar el método
valueOf()
para convertir cualquier constante String to Enum en Java, como se muestra a continuación.
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
En este fragmento de código, el método valueOf()
devuelve una constante Enum Gender.MALE, nombre de llamada que devuelve "MALE"
.
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;
}