Java proporciona un método valueOf() para cada objeto Enum<T>, así que dado un enum como

public enum Day {
  Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}

Uno puede hacer una búsqueda como

Day day = Day.valueOf("Monday");

Si la cadena pasada a valueOf() no coincide (distingue entre mayúsculas y minúsculas) un valor Day existente, se lanza un IllegalArgumentException.

Para hacer una coincidencia que no distinga entre mayúsculas y minúsculas, se puede escribir un método personalizado dentro de la enumeración Day, p. Ej.

public static Day lookup(String day) {
  for (Day d : Day.values()) {
    if (d.name().equalsIgnoreCase(day)) {
      return type;
    }
  }
  return null;
}

¿Existe alguna forma genérica, sin usar el almacenamiento en caché de valores o cualquier otro objeto adicional, para escribir un método lookup() estático como el anterior solo una vez (es decir, no para cada enum), dado que el {{ ¿El método X2}} se agrega implícitamente a la clase Enum<E> en tiempo de compilación?

La firma de un método lookup() "genérico" sería similar al método Enum.valueOf(), es decir:

public static <T extends Enum<T>> T lookup(Class<T> enumType, String name);

E implementaría exactamente la funcionalidad del método Day.lookup() para cualquier enum, sin la necesidad de volver a escribir el mismo método para cada enum.

66
PNS 5 feb. 2015 a las 01:39

9 respuestas

La mejor respuesta

Conseguir la mezcla especial de genéricos me resultó un poco complicado, pero funciona.

public static <T extends Enum<?>> T searchEnum(Class<T> enumeration,
        String search) {
    for (T each : enumeration.getEnumConstants()) {
        if (each.name().compareToIgnoreCase(search) == 0) {
            return each;
        }
    }
    return null;
}

Ejemplo

public enum Horse {
    THREE_LEG_JOE, GLUE_FACTORY
};

public static void main(String[] args) {
    System.out.println(searchEnum(Horse.class, "Three_Leg_Joe"));
    System.out.println(searchEnum(Day.class, "ThUrSdAy"));
}
48
Adam 4 feb. 2015 a las 22:58

Aún no lo he probado, pero ¿por qué no sobrecargar estos métodos como se menciona en esta SO respuesta

public enum Regular {
    NONE,
    HOURLY,
    DAILY,
    WEEKLY;

    public String getName() {
        return this.name().toLowerCase();
    }    
}
1
Ahmed Hamed 5 ago. 2020 a las 07:29

Estoy usando esta forma para la coincidencia sin distinción entre mayúsculas y minúsculas de una cadena con una enumeración de Java Day[] days = Day.values(); for(Day day: days) { System.out.println("MONDAY".equalsIgnoreCase(day.name())); }

1
Atul Jain 11 feb. 2019 a las 11:42

e implementaría exactamente la funcionalidad del método Day.lookup () para cualquier enumeración, sin la necesidad de volver a escribir el mismo método para cada enumeración.

Probablemente pueda escribir una clase de utilidad para hacer eso de la siguiente manera.

public class EnumUtil {

    private EnumUtil(){
        //A utility class
    }

    public static <T extends Enum<?>> T lookup(Class<T> enumType,
                                                   String name) {
        for (T enumn : enumType.getEnumConstants()) {
            if (enumn.name().equalsIgnoreCase(name)) {
                return enumn;
            }
        }
        return null;
    }

    // Just for testing
    public static void main(String[] args) {
        System.out.println(EnumUtil.lookup(Day.class, "friday"));
        System.out.println(EnumUtil.lookup(Day.class, "FrIdAy"));
    }

}

enum Day {
    Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}

Hubiera sido bueno si hubiera una forma en Java para que extendiéramos la clase Enum agregando métodos implícitamente de la misma manera en que se agrega el método values ​​(), pero no creo que haya una manera de hacerlo.

1
Nandana 5 feb. 2015 a las 00:12

Puede utilizar Class ' s getEnumConstants() método, que devuelve una matriz de todos los tipos de enumeración, si Class representa una enumeración, o null si no.

Devuelve los elementos de esta clase de enumeración o null si este objeto Class no representa un tipo de enumeración.

Su línea de bucle for mejorada se vería así:

for (T d : enumType.getEnumConstants()) {
4
rgettman 4 feb. 2015 a las 22:42

Una solución genérica sería mantener la convención de que las constantes son mayúsculas . (O en su caso específico use mayúsculas en la cadena de búsqueda).

public static <E extends Enum<E>> E lookup(Class<E> enumClass,
        String value) {
    String canonicalValue.toUpperCase().replace(' ', '_');
    return Enum<E>.valueOf(enumClass, canonicalValue);
}

enum Day(MONDAY, ...);
Day d = lookup(Day,class, "thursday");
5
Joop Eggen 4 feb. 2015 a las 22:58

Para Android y Enums relativamente cortos, hago el bucle simple y comparo el nombre ignorando el caso.

public enum TransactionStatuses {
    public static TransactionStatuses from(String name) {
        for (TransactionStatuses status : TransactionStatuses.values()) {
            if (status.name().equalsIgnoreCase(name)) {
                return status;
            }
        }
        return null;
    }
}
6
Alen Siljak 13 ene. 2016 a las 15:07

A partir de la versión 3.8 apache commons-lang EnumUtils tiene dos métodos útiles para esto:

  • getEnumIgnoreCase(final Class<E> enumClass, final String enumName)
  • isValidEnumIgnoreCase(final Class<E> enumClass, final String enumName)
12
Enigo 12 ene. 2018 a las 17:44

Creo que la forma más fácil y segura de hacerlo sería:

Arrays.stream(Day.values())
    .filter(e -> e.name().equalsIgnoreCase(dayName)).findAny().orElse(null);

O si desea utilizar el objeto de clase, entonces:

Arrays.stream(enumClass.getEnumConstants())
    .filter(e -> (Enum)e.name().equalsIgnoreCase(dayName)).findAny().orElse(null);
34
sprinter 10 may. 2018 a las 23:11