web-dev-qa-db-fra.com

Correspondance sans distinction de casse d'une chaîne avec une énumération Java

Java fournit une méthode valueOf() pour chaque objet Enum<T>, donc on lui donne une enum comme

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

on peut faire une recherche comme

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

Si la chaîne transmise à valueOf() ne correspond pas (en respectant la casse) à une valeur Day existante, une variable IllegalArgumentException est renvoyée.

Pour faire une correspondance ne respectant pas la casse, on peut écrire une méthode personnalisée dans l’en-tête Day, par ex.

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

Existe-t-il un moyen générique, sans utiliser la mise en cache des valeurs ni d’autres objets supplémentaires, d’écrire une seule fois la méthode lookup() statique (voir la méthode ci-dessus) (c’est-à-dire pas pour chaque enum), étant donné que la méthode values() est ajoutée implicitement à la classe Enum<E> temps de compilation?

La signature d’une telle méthode "générique" lookup() serait similaire à la méthode Enum.valueOf(), c’est-à-dire:

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

et il implémenterait exactement la fonctionnalité de la méthode Day.lookup() pour toute enum, sans qu'il soit nécessaire de réécrire la même méthode pour chaque enum.

34
PNS

J'ai trouvé difficile d'obtenir le mélange spécial de génériques, mais cela fonctionne.

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

Exemple

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"));
}
35
Adam

Je pense que le moyen le plus simple et le plus sûr de le faire serait:

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

Ou si vous voulez utiliser l'objet de classe, alors:

Arrays.stream(enumClass.getEnumConstants())
    .filter(e -> (Enum)e.name().equalsIgnoreCase(dayName)).findAny().orElse(null);
25
sprinter

Pour Android et Enum relativement courts, je fais la boucle simple et compare le nom en ignorant le cas.

public enum TransactionStatuses {
    public static TransactionStatuses from(String name) {
        for (TransactionStatuses status : TransactionStatuses.values()) {
            if (status.name().equalsIgnoreCase(name)) {
                return status;
            }
        }
        return null;
    }
}
5
Alen Siljak

Une solution générique serait de garder à la convention que les constantes sont majuscules . (Ou dans votre cas spécifique, utilisez une chaîne de majuscule sur la chaîne de recherche).

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");
4
Joop Eggen

Vous pouvez utiliser la méthode Class'S getEnumConstants() , qui renvoie un tableau de tous les types enum, si Class représente une énumération ou null sinon.

Retourne les éléments de cette classe enum ou null si cet objet Class ne représente pas un type enum.

Votre ligne améliorée pour la boucle ressemblerait à ceci:

for (T d : enumType.getEnumConstants()) {
4
rgettman

et il implémenterait exactement les fonctionnalités de Day.lookup () méthode pour toute énumération, sans qu'il soit nécessaire de réécrire la même méthode pour chaque enum.

Vous pouvez probablement écrire une classe d’utilité pour le faire comme suit. 

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
}

Cela aurait été bien s'il y avait un moyen d'utiliser Java pour étendre la classe Enum en ajoutant implicitement des méthodes de la même manière que la méthode values ​​(), mais je ne pense pas qu'il soit possible de le faire.

1
Nandana

J'utilise cette méthode pour la correspondance insensible à la casse d'une chaîne de caractères avec une énumération Java Day[] days = Day.values(); for(Day day: days) { System.out.println("MONDAY".equalsIgnoreCase(day.name())); }

0
Atul Jain