¿Cómo obtener un valor de enumeración de un valor de cadena en Java?
Frecuentes
Visto 1,231 veces
2096
29 Respuestas
2376
Sí, Blah.valueOf("A")
Te regalaré Blah.A
.
Tenga en cuenta que el nombre debe ser un exacto coincidencia, incluido el caso: Blah.valueOf("a")
y Blah.valueOf("A ")
ambos lanzan un 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.
Respondido el 09 de Septiembre de 17 a las 23:09
919
Otra solución si el texto no es el mismo que el valor de la 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;
}
}
Respondido 08 Feb 19, 14:02
throw new IllegalArgumentException("No constant with text " + text + " found")
sería mejor que return null
. - whiskyysierra
@whiskeysierra Jon Skeet no estaría de acuerdo con eso. stackoverflow.com/questions/1167982/… - Sanghyun Lee
@Sangdol Podría te lleve ilumínenos por qué devolver nulo es mejor? - whiskyysierra
@Sangdol por lo general es bueno comprobar lo que hace SUN, oops, Oracle en la misma situación. Y como Enum.valueOf () lo está mostrando IS la mejor práctica para lanzar una excepción en este caso. Gracias es una situación excepcional. La "optimización del rendimiento" es una mala excusa para escribir código ilegible ;-) - raudi
Bueno, también puedes hacer uso de la anotación @Nullable para que sea "legible" ;-) - jose mi
125
Aquí hay una ingeniosa utilidad que utilizo:
/**
* 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 ahorrar algo de escritura:
public static MyEnum fromString(String name) {
return getEnumFromString(MyEnum.class, name);
}
Si sus enumeraciones no son todas en mayúsculas, simplemente cambie el Enum.valueOf
la línea.
Lástima que no pueda usar T.class
es Enum.valueOf
as T
se borra.
respondido 17 nov., 14:20
Ese bloque de captura vacío realmente me vuelve loco, lo siento. - whiskyysierra
@LazloBonin: Las excepciones son para condiciones excepcionales, no para control de flujo. Consíguete una copia de Java eficaz. - Martín Schröder
Si la API de Java que desea usar arroja una excepción y no desea que su código arroje una, puede tragarse la excepción de esta manera o reescribir la lógica desde cero para que no se lance ninguna excepción en primer lugar. Tragarse la excepción es a menudo el mal menor. - Nate CK
¡Horrible! Siempre, siempre detecta excepciones donde puedas manejarlas. El ejemplo anterior es un ejemplo perfecto como NO hacerlo. ¿Por qué? Por lo tanto, devuelve NULL, y la persona que llama tiene que verificar NULL o lanzar una NPE. Si la persona que llama sabe cómo manejar la situación, entonces hacer un if vs try-catch puede parecer un poco más elegante, PERO si no puede manejar, tiene que pasar null nuevamente y la persona que llama de la persona que llama de nuevo tiene que comprobar contra NULL, etc., etc. - raudi
Para ser justos con la solución anterior, realmente hay casos de usos que requieren que devuelva nulo en lugar de lanzar IllegalArgumentException y romper el flujo de su programa, por ejemplo, asignando enumeraciones entre un esquema de servicio web y un esquema de base de datos en los que no siempre son uno. -a uno. Sin embargo, estoy de acuerdo en que el bloque de captura nunca debe dejarse vacío. Ponga algún código como log.warn o algo con fines de seguimiento. - Adrian M
120
Usa el patrón de Joshua Bloch, Java eficaz:
(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().toLowerCase(),instance);
}
ENUM_MAP = Collections.unmodifiableMap(map);
}
public static MyEnum get (String name) {
return ENUM_MAP.get(name.toLowerCase());
}
}
Ver también:
Ejemplo de Oracle Java usando Enum y Map de instancias
Orden de ejecución de bloques estáticos en un tipo Enum
¿Cómo puedo buscar una enumeración de Java a partir de su valor de cadena?
Respondido el 30 de diciembre de 20 a las 22:12
si Joshua Bloch lo dijo, entonces este es el único camino a seguir :-). Es una pena que siempre tenga que desplazarme hacia abajo. - dermoritz
Esto es aún más simple en Java 8 como puede hacer:Stream.of(MyEnum.values()).collect(toMap(Enum::name, identity()))
También recomiendo anular toString () (pasado a través del constructor) y usar eso en lugar del nombre, especialmente si Enum está asociado con datos serializables, ya que esto le permite controlar la carcasa sin darle un ajuste a Sonar. - Novaterata
Java 8 ciertamente puede / cambiará muchas (mejores) respuestas en este foro. Sin embargo, no estoy seguro de que la cola (Sonar) mueva al perro (código de aplicación). - Darrell Teague
Si vas a ponerlo en un unmodifiableMap
de todos modos, no hay ningún beneficio en comenzar con un ConcurrentHashMap
. Solo usa un HashMap
. (Si tiene Guayaba ImmutableMap
¡Entonces lo recomendaría en su lugar!) - daniel priden
La inicialización estática está intrínsecamente sincronizada, por lo que no hay absolutamente ninguna razón para usar ConcurrentHashMap
aquí, donde el mapa nunca se modifica después de la inicialización. De ahí por qué incluso, por ejemplo, el ejemplo en el propio JLS utiliza un HashMap
. - radiodef
77
También debe tener cuidado con su caso. Déjame explicarte: haciendo Blah.valueOf("A")
funciona, pero Blah.valueOf("a")
no trabajará. Luego otra vez Blah.valueOf("a".toUpperCase(Locale.ENGLISH))
funcionaría.
editar
cambiado toUpperCase
a toUpperCase(Locale.ENGLISH)
basados en tc. comentario y el documentos java
edit2
En Android deberías usar Locale.US
, ya que Sulai señala.
contestado el 23 de mayo de 17 a las 13:05
¡Tenga cuidado con la configuración regional predeterminada! - tc.
Para los usuarios de Android, me gustaría señalar que Documentación de Android fomenta explícitamente el uso de Locale.US
para entrada / salida legible por máquina. - sulai
@Trengot Sí, lamentablemente. Turquía es un buen ejemplo. Combine esto con el manejo defectuoso de Java de los juegos de caracteres predeterminados (por defecto es latín en Windows en lugar de Unicode) y encontrará que casi siempre es inseguro usar las versiones predeterminadas de métodos que aceptan un juego de caracteres o una configuración regional. Casi siempre debería definirlos explícitamente. - Stijn de Witt
No estoy seguro de que los conjuntos de caracteres "predeterminados" de Java y otros estén "rotos" per se, pero se otorgan, el uso predeterminado de UTF-8 en lugar de anulaciones (que deben hacerse siempre para ser explícitos) habría hecho mejores sistemas para programadores junior que comúnmente no comprenden conceptos de juego de caracteres. - Darrell Teague
46
En Java 8 o posterior, usando Arroyos:
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();
}
}
Respondido 26 Abr '19, 12:04
No estoy seguro de que esta sea una mejor respuesta. En este caso, los flujos son un iterador de un solo subproceso como cualquier otro sobre todos los valores y posiblemente menos rendimiento que un impl de búsqueda de mapa. Las secuencias tienen más valor en un contexto de subprocesos múltiples donde, por ejemplo, la ejecución paralela de un archivo de texto separado por líneas nuevas puede mejorar el rendimiento. - Darrell Teague
@DarrellTeague Si mide la diferencia de nanosegundos entre la solución Streams y la solución de búsqueda de mapas, verá una diferencia. Sin embargo, creo que en el mundo real no habrá una diferencia de rendimiento apreciable a menos que tenga una enumeración bastante grande, que es una excepción a la regla en mi opinión. Además, el enfoque de Streams es compacto y legible, aunque estoy seguro de que también podría presentar el mismo argumento para la implementación del mapa: Flaom
38
Aquí hay un método que puede hacerlo para cualquier Enum y no distingue entre 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()
));
}
Respondido 22 Abr '15, 22:04
Esta variación lo está haciendo correctamente: equalsIgnoreCase
es el camino a seguir. +1 - Stijn de Witt
Como la insensibilidad a mayúsculas y minúsculas, pero ... prefiero Enums sobre asignaciones de cadenas (aleatorias) para claves y ... menor, pero la iteración es menos eficaz para una búsqueda tan posiblemente repetitiva. Por lo tanto impl de EnumMap et al. - Darrell Teague
Esto no funciona ! Cambié equalsIgnoreCase a equals para mi propósito. El código falló a pesar de que ambas entradas a iguales eran exactamente iguales. - maestrojoe
37
Usar Blah.valueOf(string)
es mejor pero puedes usar Enum.valueOf(Blah.class, string)
.
Respondido 12 ago 13, 02:08
Sensible a mayúsculas y minúsculas, ¡no ayuda! - Murtaza Kanchwala
@MurtazaKanchwala ¿Puedes aclarar tu comentario? ¿Que estás tratando de hacer? - pedro laurey
Hola @PeterLawrey, estaba intentando obtener una enumeración de una cadena pública enum ObjectType {PERSON ("Persona") public String parameterName; ObjectType (String parameterName) {this.parameterName = parameterName; } public String getParameterName () {return this.parameterName; } public static ObjectType fromString (String parameterName) {if (parameterName! = null) {for (ObjectType objType: ObjectType.values ()) {if (parameterName.equalsIgnoreCase (objType.parameterName)) {return objType; }}} devuelve nulo; }} - Murtaza Kanchwala
32
Mis 2 centavos aquí: usando Java8 Streams + verificando 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()
ya que lo nombra usando esa convención, obtendrá algunos beneficios del lenguaje Java en sí; por ejemplo:
Respondido el 09 de enero de 19 a las 09:01
Alternativamente para permitirle escribir más legible switch
bloques, puedes .orElse(null)
en lugar de .orElseThrow()
para que pueda codificar la excepción, agregue el default
cláusula - e incluya información más útil cuando sea necesario. Y para hacerlo más indulgente, podrías usar v -> Objects.equals(v.name, s == null ? "" : s.trim().toUpperCase())
- Adam
o simplemente devuelve el Optional
a partir de octubre XNUMX findFirst()
, permitiendo al usuario decidir si quiere .orElse(null)
, orElseThrow()
o lo que sea.... - user85421
En mi opción, es mejor evitar Excepciones y usar Opcional. Además de eso, deberíamos anular null y usar Optional en su lugar también. - hans schreuder
Nuevamente, recuerde que incluso si el código tiene menos o mejor apariencia ... una implementación de Stream como esta es solo un iterador sobre todos los valores versus una búsqueda de mapa (menos rendimiento). - Darrell Teague
29
Si no desea escribir su propia utilidad, utilice la de Google guayaba biblioteca:
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.
Respondido 02 Abr '14, 21:04
La parte triste es que esto devuelve un Opcional de Google y no un Opcional de Java - programador java
Cierto. Sin embargo, exultante. Google y Netflix tienen excelentes bibliotecas de Java. Donde hay una superposición con las clases de actualización de Java implementadas en versiones más nuevas, inevitablemente causa problemas. Algo que tiene que ser todo en un proveedor lib. - Darrell Teague
16
Puede que necesite 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 enumeración en cadena. Por ejemplo, si proporciona "PERSON" en fromEnumName, le devolverá el valor de Enum, es decir, "Persona"
Respondido 29 Oct 15, 14:10
13
Otra forma de hacer esto mediante el uso de un método estático implícito name()
de Enum. name devolverá la cadena exacta utilizada para crear esa enumeración que se puede usar para verificar 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
respondido 29 nov., 11:05
Esto es esencialmente lo que valueOf
hace por ti. Este método estático no ofrece nada adicional, excepción y todo. Entonces, las construcciones if / else son altamente peligrosas ... cualquier nueva constante de enumeración agregada hará que este método se rompa sin cambios. - Yoyó
Considere también este ejemplo de cómo podemos usar valueOf para realizar una búsqueda que no distingue entre mayúsculas y minúsculas, o cómo podemos evitar su excepción y emplear alias para proporcionar nombres alternativos: stackoverflow.com/a/12659023/744133 - Yoyó
name()
no es estático. - nrubin29
10
Solución utilizando bibliotecas de Guava. 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();
}
}
Respondido 23 ago 14, 03:08
8
Para agregar a las respuestas anteriores y abordar algunas de las discusiones sobre nulos y NPE, estoy usando Guava Optionals para manejar casos ausentes / inválidos. Esto funciona muy bien para el análisis de URI / 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 más información sobre cómo evitar nulos con Opcional: https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained#Optional
Respondido 22 Abr '15, 22:04
Esta es una respuesta realmente buena para los patrones relacionados y el uso de Optional dentro de una Enum, aprovechando el hecho de que las Enums también son clases y, por lo tanto, se pueden decorar con métodos, métodos de anulación, etc. Los nulos devueltos por los métodos hacen que la construcción tenga errores (NPE en lugares desconocidos en las cadenas de Fluent de llamadas a métodos). - Darrell Teague
8
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 usar Enum con Jackson, puede anular toString y usar eso en lugar del nombre, 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);
}
}
Respondido 27 Abr '17, 18:04
Jackson es una implementación JSON (JavaScript Object Notation). La pregunta original no tenía nada que ver con JSON. - Darrell Teague
La parte JSON era solo un material adicional que encontré relevante en ese momento, ya que obtener un Enum de una cadena es básicamente un tipo de deserialización y JSON / Jackson es probablemente la solución de serialización más popular. - Novaterata
Comprender, pero desde el punto de vista de la moderación, no contribuyó a responder la pregunta del OP, así que solo trato de ayudar a establecer el contexto allí.JSON es de hecho el camino a seguir para convertir objetos a forma canónica en Java con Jackson como una gran biblioteca. - Darrell Teague
8
Enum es muy útil, he estado usando Enum
mucho para agregar una descripción para algunos campos en diferentes idiomas, como el siguiente ejemplo:
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;
}
}
Y luego puede recuperar la descripción dinámicamente basada en el código de idioma pasado a getDescription(String lang)
método, por ejemplo:
String statusDescription = Status.valueOf("ACT").getDescription("en");
Respondido el 23 de junio de 19 a las 09:06
Buen ejemplo de impulsar Enums aún más. Habría hecho la codificación del idioma usando los nombres estáticos estándar y la búsqueda en un mapa, pero aún así ... un buen ejemplo de tener una enumeración con diferentes etiquetas para lo que es esencialmente el mismo valor lógico. - Darrell Teague
6
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;
}
Respondido 22 Abr '15, 22:04
Eche un vistazo a este enlace para obtener guías sobre cómo responder y hacer preguntas en stackoverflow.com: stackoverflow.com/faq - bakoyaro
Eso es más o menos lo mismo que la respuesta de JoséMi: O
6
Método O (1) inspirado en código generado de 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;
}
}
Respondido el 23 de Septiembre de 15 a las 10:09
Tenga en cuenta que los identificadores cero (0) y uno (1) son innecesarios. El método Enum values () devolverá los miembros en el mismo orden en que se codificaron. Por lo tanto, la primera entrada será el cero ordinal, la segunda, etc. Darrell Teague
5
Apache commons-lang la biblioteca tiene una función estática org.apache.commons.lang3.EnumUtils.getEnum que asignará una cadena a su tipo de enumeración. Esencialmente, la misma respuesta que Geoffreys, pero ¿por qué lanzar la suya propia cuando ya está disponible en la naturaleza?
Respondido 22 Oct 15, 07:10
Comentario justo (DRY) pero ... aunque la mayoría de las cosas de Apache Commons son geniales, yo mismo encontré varios errores y anti-patrones en esa base. Por lo tanto, refiriéndose a decir que la implementación de Joshua Bloch puede tener una base más sólida. Luego se reduce a tener que revisar el código de Apache para saber qué implementó alguien. Si fuera el famoso Doug Leah quien reescribió la concurrencia de Java ... entonces confiaría implícitamente en él. - Darrell Teague
5
¿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();
}
}
}
Respondido el 30 de diciembre de 17 a las 07:12
4
java.lang.Enum
define varios métodos útiles, que están disponibles para todos los tipos de enumeración en Java:
- Puedes usar
name()
método para obtener el nombre de cualquier constante Enum. El literal de cadena utilizado para escribir constantes de enumeración es su nombre. - Del mismo modo
values()
El método se puede usar para obtener una matriz de todas las constantes Enum de un tipo Enum. - Y para la pregunta formulada, puede usar
valueOf()
método para convertir cualquier cadena en constante 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, valueOf()
El método devuelve una constante Enum Gender.MALE, llamando al nombre que devuelve "MALE"
.
Respondido 22 Abr '15, 22:04
4
Agregando a la respuesta mejor calificada, con una utilidad útil ...
valueOf()
arroja 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 String definitivamente coincidirá con un valor de enumeración, por ejemplo, si los datos de String provienen de una base de datos y podrían contener una versión anterior de la enumeración, entonces deberá manejarlos. a menudo...
Así que aquí hay un método reutilizable que escribí que nos permite definir una enumeración predeterminada 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;
}
}
Úselo 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
}
Respondido 11 Jul 17, 18:07
3
Como switch
-La versión aún no se ha mencionado, la presento (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);
}
}
}
Dado que esto no da ningún valor adicional a la valueOf(String name)
método, solo tiene sentido definir un método adicional si queremos tener un comportamiento diferente. Si no queremos levantar un 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 contrato of Enum.valueOf(String name)
sin tirar un IllegalArgumentException
de esa manera que en ningún caso null
es regresado. Por lo tanto, lanzamos un NullPointerException
si el nombre es null
y en caso de default
if defaultValue
is null
. Así es como valueOfOrDefault
obras.
Este enfoque adopta el diseño del Map
-Interfaz que proporciona un método Map.getOrDefault(Object key, V defaultValue)
a partir de Java 8.
Respondido 02 ago 18, 22:08
1
Otra utilidad que captura a la inversa. Usando un valor que identifique esa enumeración, no por 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")
devoluciones Foo.THREE
, porque usará getValue
para que coincida con "drei", que es un método público único, no final y no estático en Foo. En caso de que Foo tenga más de un método público, no final ni estático, por ejemplo, getTranslate
que devuelve "drei", se puede utilizar el otro método: EnumUtil.from(Foo.class, "drei", "getTranslate")
.
Respondido 24 Feb 16, 11:02
1
Estaba buscando una respuesta para encontrar el nombre "bla" y no su valor (no el texto). basado en @Manu (@Mano) respuesta Encuentro este código útil:
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 valueOfCode(String blahCode) throws IllegalArgumentException {
Blah blah = Arrays.stream(Blah.values())
.filter(val -> val.name().equals(blahCode))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Unable to resolve blah : " + blahCode));
return blah;
}
}
Respondido el 29 de diciembre de 20 a las 11:12
1
Enum valueOf () Una clase enum obtiene automáticamente un método valueOf () estático en la clase cuando se compila. El método valueOf () se puede usar para obtener una instancia de la clase enum para un valor String dado. Por ejemplo: -
public class Main {
public static void main(String[] args) throws Exception {
System.out.println(Strings.TWO.name());
}
enum Strings {
ONE, TWO, THREE
}}
respondido 05 mar '21, 06:03
0
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 que se devuelva cuando las otras no se encuentran (incluso sin distinción 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;
}
Respondido 30 ago 16, 10:08
0
Solución de Kotlin
Crea una extensión y luego llama valueOf<MyEnum>("value")
. Si el tipo no es válido, obtendrá nulo y tendrá que manejarlo
inline fun <reified T : Enum<T>> valueOf(type: String): T? {
return try {
java.lang.Enum.valueOf(T::class.java, type)
} catch (e: Exception) {
null
}
}
Alternativamente, puede establecer un valor predeterminado, llamando valueOf<MyEnum>("value", MyEnum.FALLBACK)
y evitando una respuesta nula. Puede extender su enumeración específica para que el valor predeterminado sea 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
}
}
O si quieres ambos, haz el segundo:
inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T = valueOf<T>(type) ?: default
Respondido el 18 de enero de 20 a las 00:01
¿Crees que tu respuesta tendrá un mejor hogar aquí? stackoverflow.com/questions/28548015/… - charlatán
Esta no es una pregunta de Kotlin. - Shinzou
Esto es similar a Js / jQuery. Cuando los desarrolladores de Android buscan una solución, terminan buscando Java y luego traduciendo a Kotlin. Esta es una solución no obvia, mejor que una traducción directa. Los motores de búsqueda no dejarán de priorizar esta solución en el corto plazo, es mejor simplemente ayudar a esos desarrolladores a encontrar rápidamente una buena solución. Está marcado como Kotlin, los desarrolladores de Java pueden omitirlo: Gibolt
0
La forma más rápida de obtener el nombre de la enumeración es crear un mapa de texto y valor de enumeración cuando se inicia la aplicación, y para obtener el nombre, llame a la función 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());
}
}
respondido 31 mar '20, 07:03
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas java enums or haz tu propia pregunta.
Como referencia, el
Blah.valueOf("A")
el método es distingue mayúsculas y minúsculas y no tolera espacios en blanco extraños, por lo tanto, la solución alternativa propuesta a continuación por @ JoséMi. - Bordo@Michael Myers, dado que esta respuesta es la más votada con diferencia, ¿debo entender que es una buena práctica definir una enumeración y su valor de cadena para que sean exactamente iguales? - kevin meredith
@KevinMeredith: Si te refieres al
toString()
valor, no, yo no diría eso.name()
obtendrá el nombre real definido de la constante de enumeración a menos que lo anule. - Michael Myers ♦¿Qué quiere decir exactamente con "se crean en tiempo de compilación y no aparecen en el código fuente"? ? - árbolesAreEverywhere
@treesAreEverywhere Más específicamente, esos métodos son generado (o sintetizado) por el compilador. El actual
enum Blah {...}
la definición no debería intentar declararse propiavalues
nivaluesOf
. Es como escribir "AnyTypeName.class" aunque nunca haya declarado una variable miembro de "clase"; el compilador hace que todo funcione. (Es posible que esta respuesta ya no le sea útil 3 meses después, pero por si acaso). Ti Strga