Groß-/Kleinschreibungsunabhängiger Abgleich einer Zeichenfolge mit einer Java-Enumeration

Lesezeit: 5 Minuten

Benutzer-Avatar
PNS

Java bietet ein valueOf() Methode für alle Enum<T> Objekt, also gegeben an enum wie

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

man kann nachschlagen wie

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

Wenn die Zeichenfolge übergeben wird valueOf() stimmt nicht mit einem vorhandenen überein (Groß-/Kleinschreibung beachten). Day Wert, ein IllegalArgumentException ist geworfen.

Um einen Vergleich ohne Berücksichtigung der Groß-/Kleinschreibung durchzuführen, kann man eine benutzerdefinierte Methode in die schreiben Day Aufzählung, zB

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

Gibt es eine generische Möglichkeit, ohne das Zwischenspeichern von Werten oder anderen zusätzlichen Objekten zu verwenden, um eine Statik zu schreiben lookup() Methode wie oben nur einmal (also nicht für jeden enum), da die values() -Methode wird implizit zu hinzugefügt Enum<E> Klasse zur Kompilierzeit?

Die Signatur eines solchen “Generikums” lookup() Methode wäre ähnlich wie die Enum.valueOf() Methode, dh:

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

und es würde genau die Funktionalität der implementieren Day.lookup() Methode für alle enumohne die gleiche Methode für jede neu schreiben zu müssen enum.

  • Ich bin sicher, Sie wissen es, aber der Grund, warum das Problem jemals aufgetreten ist, ist, dass Sie sich nicht an die Namenskonvention für Java-Enumerationen halten. Wenn Sie die Standardbenennung in Großbuchstaben verwenden würden, würden Sie einfach verwenden Day.valueOf(day.toUpperCase()) in Ihrer Suchmethode

    – Kiedysktos

    23. Mai 2017 um 8:30 Uhr


  • Nein, die gleiche Anforderung gilt unabhängig von der Groß- und Kleinschreibung oder anderen Namenskonventionen. Eine gemeinsame Methode für alle Zwecke war die Anfrage. 🙂

    – PNS

    25. Mai 2017 um 1:15 Uhr

  • Ergänzend zu @kiedysktos Vorschlag (der für alle anderen Leser bei weitem die einfachste Lösung ist), vermute ich, dass OP gegen die Namenskonvention verstoßen hat, weil sie möchten, dass das toString-Formular nur den ersten Buchstaben in Großbuchstaben enthält, wie es grammatikalisch korrektes Englisch ist. Sie können dies immer noch erreichen, indem Sie die Methode toString überschreiben: return super.toString().substring(0, 1).toUpperCase() + super.toString().substring(1);

    – Rurouniwallace

    14. November 2018 um 8:44 Uhr

Ich fand es etwas schwierig, die spezielle Mischung von Generika zu bekommen, aber das funktioniert.

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

Beispiel

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

  • Ja, das funktioniert. Danke für den Hinweis auf die getEnumConstants() Methode. Ich habe eigentlich versucht, den Anruf zu vermeiden values() Methode über Reflexion, was die ist getEnumConstants() tut es tatsächlich, aber anscheinend gibt es keinen besseren Ansatz. Übrigens können Sie einfach verwenden equalsIgnoreCase() für den Saitenvergleich.

    – PNS

    4. Februar 2015 um 23:56 Uhr


  • Würde es sich lohnen, die Werte einmal in einer Karte zwischenzuspeichern, anstatt sie jedes Mal zu wiederholen? z.B Map<String, MyEnum> wo der Wert bereits kleingeschrieben ist oder so.

    – jokul

    25. April 2019 um 20:14 Uhr


  • Reflektion ist schnell genug, aber Caching ist schneller, also ja, es wäre sinnvoll für bestimmte Enums oder wenn die Methode nur für wenige Enums aufgerufen würde. In dem in der Frage beschriebenen Anwendungsfall ist Caching nicht anwendbar, da die lookup Methode ist völlig generisch.

    – PNS

    5. März 2021 um 16:50 Uhr

Benutzer-Avatar
Sprinter

Ich denke, der einfachste sichere Weg, dies zu tun, wäre:

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

Oder wenn Sie das Klassenobjekt verwenden möchten, dann:

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

  • Hmm… Die values() Methode ist für die nicht verfügbar enumType Parameter, der vom Typ ist Class<T>.

    – PNS

    5. Februar 2015 um 0:04 Uhr

  • @PNS Ich hatte gedacht, das wäre der Enum-Name. Ich habe mich geändert, um die Aufzählung im Beispiel zu verwenden.

    – Sprinter

    5. Februar 2015 um 1:48 Uhr

Ab Version 3.8 Apache Commons-Sprache EnumUtils hat zwei praktische Methoden dafür:

  • getEnumIgnoreCase(final Class<E> enumClass, final String enumName)
  • isValidEnumIgnoreCase(final Class<E> enumClass, final String enumName)

  • Ich sehe 3.8 nicht im Maven-Repository.

    – Benutzer2180794

    20. März 2018 um 6:21 Uhr

Eine generische Lösung wäre, sich an die Konvention zu halten Konstanten werden in Großbuchstaben geschrieben. (Oder verwenden Sie in Ihrem speziellen Fall einen Großbuchstaben für die Suchzeichenfolge).

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");

Benutzer-Avatar
Alen Siljak

Für Android und relativ kurze Enums mache ich die einfache Schleife und vergleiche den Namen, wobei ich die Groß- und Kleinschreibung ignoriere.

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

Benutzer-Avatar
rgettman

Sie können verwenden Class‘s getEnumConstants() Methodedie ein Array aller Aufzählungstypen zurückgibt, wenn die Class stellt eine Aufzählung dar, oder null wenn nicht.

Gibt die Elemente dieser Aufzählungsklasse zurück oder null, wenn dieses Klassenobjekt keinen Aufzählungstyp darstellt.

Ihre erweiterte for-Schleife würde wie folgt aussehen:

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

Benutzer-Avatar
gbtimmon

Ich kann das glauben, oder eine ähnliche Lösung wurde noch nicht gepostet. Meine bevorzugte Anlaufstelle hier (es besteht absolut keine Notwendigkeit für ein ‘Nachschlagen’, nur ein klügeres valueOf. Außerdem sind Enum-Werte als Bonus alle in Großbuchstaben, wie wir ehemaligen C++-Anwender denken, dass sie es sein sollten …

public enum Day {
    MONDAY("Monday"), 
    TUESDAY("Tuesday"), 
    WEDNESDAY("Wednesday"),
    THURSDAY("Thursday"), 
    FRIDAY("Friday"),
    SATURDAY("Saturday"),
    SUNDAY("Sunday"); 

    public static Day valueOfIgnoreCase(String name) {
         return valueOf(name.toUpperCase());
    }

    private final String displayName; 

    Day(String displayName) {
        this.displayName = displayName;
    }

    @Override
    public String toString() {
        return this.displayName; 
    }
}

Und dann:

Day day = Day.valueOfIgnoreCase("mOnDay"); 
System.out.println(day); 

>>> Monday

1146300cookie-checkGroß-/Kleinschreibungsunabhängiger Abgleich einer Zeichenfolge mit einer Java-Enumeration

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy