Heim > System-Tutorial > LINUX > Hauptteil

Vergleich der Vor- und Nachteile mehrerer Java-Enumerations-Lookup-Implementierungen, die keine Ausnahmen auslösen

PHPz
Freigeben: 2024-01-03 13:24:56
nach vorne
532 Leute haben es durchsucht
Einführung Java Enum ist eine sehr nützliche Funktion, aber viele Leute nutzen sie oft nicht in vollem Umfang, da einige Bibliotheken dieser Funktion keine Priorität einräumen. Normalerweise können wir die Java-Aufzählungsfunktion auch korrekt verwenden, aber in vielen Codebasen gibt es häufig ein solches Problem, weshalb dieser Artikel geschrieben wurde. Die Frage ist einfach: Wie sollen wir eine Enumeration nach Name oder Wert erhalten und nicht vorhandene Werte ignorieren?
Aufzählung

Dies ist die Aufzählung, die wir in unserem Beispiel verwenden werden. Die komplexere Aufzählung wird ausgewählt, damit die Nachschlageaufzählung auch durch andere Felder dargestellt werden kann.

public enum CardColor {
    RED,
    BLACK,
    ;
}
// Jackson annotation to print the enum as an Object instead of the default name.
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum CardSuit {
    // Unicode suits - https://en.wikipedia.org/wiki/Playing_cards_in_Unicode
    SPADE("Spade", String.valueOf((char) 0x2660), CardColor.BLACK),
    HEART("Heart", String.valueOf((char) 0x2665), CardColor.RED),
    DIAMOND("Diamond", String.valueOf((char) 0x2666), CardColor.RED),
    CLUB("Club", String.valueOf((char) 0x2663), CardColor.BLACK),
    ;
    private String displayName;
    private String symbol;
    private CardColor color;
    private CardSuit(String displayName, String symbol, CardColor color) {
        this.displayName = displayName;
        this.symbol =  symbol;
        this.color = color;
    }
    public String getDisplayName() {
        return displayName;
    }
    public void setDisplayName(String displayName) {
        this.displayName = displayName;
    }
    public String getSymbol() {
        return symbol;
    }
    public void setSymbol(String symbol) {
        this.symbol = symbol;
    }
    public CardColor getColor() {
        return color;
    }
    public void setColor(CardColor color) {
        this.color = color;
    }
Nach dem Login kopieren

Sehen Sie es sich auf GitHub an.

Frage

Die Verwendung von Enum.valueOf ist großartig, wenn Sie wissen, dass die Eingabe gültig ist. Wenn jedoch ein ungültiger Name übergeben wird, wird eine Ausnahme ausgelöst. In manchen Fällen ist das in Ordnung. Im Allgemeinen ignorieren wir die Ausnahme jedoch lieber und geben null zurück.

log.debug("Running valueOf");
for (String name : names) {
    try {
        log.debug("looking up {} found {}", name, Json.serializer().toString(CardSuit.valueOf(name)));
    } catch (Exception ex) {
        log.warn("Exception Thrown", ex);
    }
}
Nach dem Login kopieren

2017-02-22 14:46:38.556 [main] DEBUG c.s.examples.common.EnumLookup - Running valueOf
2017-02-22 14:46:38.804 [main] DEBUG c.s.examples.common.EnumLookup - looking up SPADE found {"displayName":"Spade","symbol":"♠","color":"BLACK"}
2017-02-22 14:46:38.806 [main] DEBUG c.s.examples.common.EnumLookup - looking up HEART found {"displayName":"Heart","symbol":"♥","color":"RED"}
2017-02-22 14:46:38.806 [main] DEBUG c.s.examples.common.EnumLookup - looking up DIAMOND found {"displayName":"Diamond","symbol":"♦","color":"RED"}
2017-02-22 14:46:38.806 [main] DEBUG c.s.examples.common.EnumLookup - looking up CLUB found {"displayName":"Club","symbol":"♣","color":"BLACK"}
2017-02-22 14:46:38.808 [main] WARN  c.s.examples.common.EnumLookup - Exception Thrown
java.lang.IllegalArgumentException: No enum constant com.stubbornjava.examples.common.EnumLookup.CardSuit.Missing
  at java.lang.Enum.valueOf(Enum.java:238)
  at com.stubbornjava.examples.common.EnumLookup$CardSuit.valueOf(EnumLookup.java:1)
  at com.stubbornjava.examples.common.EnumLookup.main(EnumLookup.java:154)
Nach dem Login kopieren
Schlechte Umsetzung

Leider kommen die folgenden beiden Methoden so häufig in der Codebasis vor. Lernen Sie nicht aus negativen Beispielen.

Enum.valueOf mit Try Catch (schlecht)

Diese schlechte Praxis kommt am häufigsten bei Anfängern vor. Ausnahmen sollten nicht für die Ablaufsteuerung verwendet werden, da dies möglicherweise Auswirkungen auf die Leistung haben kann. Seien Sie nicht faul. Man muss es richtig machen.

/*
 * Please don't do this! Using try / catch for
 * control flow is a bad practice.
 */
public static CardSuit trycatchValueOf(String name) {
    try {
        return CardSuit.valueOf(name);
    } catch (Exception ex) {
        log.warn("Exception Thrown", ex);
        return null;
    }
}
Nach dem Login kopieren

log.debug("Running trycatchValueOf");
for (String name : names) {
    log.debug("looking up {} found {}", name, Json.serializer().toString(CardSuit.trycatchValueOf(name)));
}
Nach dem Login kopieren

2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - Running trycatchValueOf
2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up SPADE found {"displayName":"Spade","symbol":"♠","color":"BLACK"}
2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up HEART found {"displayName":"Heart","symbol":"♥","color":"RED"}
2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up DIAMOND found {"displayName":"Diamond","symbol":"♦","color":"RED"}
2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up CLUB found {"displayName":"Club","symbol":"♣","color":"BLACK"}
2017-02-22 14:46:38.809 [main] WARN  c.s.examples.common.EnumLookup - Exception Thrown
java.lang.IllegalArgumentException: No enum constant com.stubbornjava.examples.common.EnumLookup.CardSuit.Missing
  at java.lang.Enum.valueOf(Enum.java:238)
  at com.stubbornjava.examples.common.EnumLookup$CardSuit.valueOf(EnumLookup.java:1)
  at com.stubbornjava.examples.common.EnumLookup$CardSuit.trycatchValueOf(EnumLookup.java:89)
  at com.stubbornjava.examples.common.EnumLookup.main(EnumLookup.java:171)
2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up Missing found null
Nach dem Login kopieren
Suchen nach Iteration (minderwertig)

Diese Methode ist auch sehr verbreitet (siehe hier), aber zumindest weiß der Programmierer, dass try/catch nicht zum Abfangen von Ausnahmen verwendet werden kann. Was ist also falsch an diesem Ansatz? Das ist richtig, es durchläuft alle Aufzählungen, bis es eine passende Aufzählung findet oder null zurückgibt – im schlimmsten Fall n-mal, wobei n die Anzahl der Aufzählungswerte ist. Manche denken vielleicht, dass dies eine triviale und einfach verfrühte Optimierung ist. Datenstrukturen und Algorithmen sind jedoch die Grundlage von CS. Es ist viel weniger aufwändig, eine Map zu verwenden, anstatt eine Sammlung zu durchlaufen. Wird dies die Leistung erheblich verbessern? Nein, aber es ist eine gute Angewohnheit, sich anzueignen. Würden Sie sich bei Bewerbungsgesprächen mit einem linearen Komplexitätssuchalgorithmus wohl fühlen? An dieser Stelle sollten Sie eine solche Codeüberprüfung nicht verstreichen lassen.

/*
 * Please don't do this! It is inefficient and it's
 * not very hard to use Guava or a static Map as an index.
 */
public static CardSuit iterationFindByName(String name) {
    for (CardSuit suit : CardSuit.values()) {
        if (name.equals(suit.name())) {
            return suit;
        }
    }
    return null;
}
Nach dem Login kopieren

log.debug("Running iteration");
for (String name : names) {
    log.debug("looking up {} found {}", name, Json.serializer().toString(CardSuit.iterationFindByName(name)));
}
Nach dem Login kopieren

2017-02-22 14:46:38.808 [main] DEBUG c.s.examples.common.EnumLookup - Running iteration
2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up SPADE found {"displayName":"Spade","symbol":"♠","color":"BLACK"}
2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up HEART found {"displayName":"Heart","symbol":"♥","color":"RED"}
2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up DIAMOND found {"displayName":"Diamond","symbol":"♦","color":"RED"}
2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up CLUB found {"displayName":"Club","symbol":"♣","color":"BLACK"}
2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up Missing found null
Nach dem Login kopieren
Bessere Umsetzung

Das Folgende kann durch die Verwendung von Indizes in Kartenform funktionieren. Es gibt jedoch einige subtile Unterschiede zwischen ihnen.

Statischer Kartenindex (besser)

Was ist die richtige Datenstruktur für eine schnelle Suche mit fester Größe? Das ist HashMap. Mit etwas mehr Boilerplate können wir jetzt effizientere Suchvorgänge durchführen, vorausgesetzt, wir haben eine gute Hash-Funktion. Etwas ausführlicher, aber es wäre toll, wenn es eine Möglichkeit gäbe, den Boilerplate zu reduzieren.

private static final Map<String, CardSuit> nameIndex =
        Maps.newHashMapWithExpectedSize(CardSuit.values().length);
static {
    for (CardSuit suit : CardSuit.values()) {
        nameIndex.put(suit.name(), suit);
    }
}
public static CardSuit lookupByName(String name) {
    return nameIndex.get(name);
}
Nach dem Login kopieren
log.debug("Running lookupByName");
for (String name : names) {
    log.debug("looking up {} found {}", name, Json.serializer().toString(CardSuit.lookupByName(name)));
}
Nach dem Login kopieren
2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - Running lookupByName
2017-02-22 14:46:38.809 [main] DEBUG c.s.examples.common.EnumLookup - looking up SPADE found {"displayName":"Spade","symbol":"♠","color":"BLACK"}
2017-02-22 14:46:38.810 [main] DEBUG c.s.examples.common.EnumLookup - looking up HEART found {"displayName":"Heart","symbol":"♥","color":"RED"}
2017-02-22 14:46:38.810 [main] DEBUG c.s.examples.common.EnumLookup - looking up DIAMOND found {"displayName":"Diamond","symbol":"♦","color":"RED"}
2017-02-22 14:46:38.813 [main] DEBUG c.s.examples.common.EnumLookup - looking up CLUB found {"displayName":"Club","symbol":"♣","color":"BLACK"}
2017-02-22 14:46:38.813 [main] DEBUG c.s.examples.common.EnumLookup - looking up Missing found null
Nach dem Login kopieren
Guava Enums.getIfPresent (empfohlen)

Dies ist ein häufiger Anwendungsfall und unsere Freunde bei Google haben dafür eine sehr saubere und einfache Lösung. Unter der Haube werden sogar WeakReferences und WeakHashMaps verwendet. Im Grunde erstellt dieser Code eine globale statische Karte, die im Enum-Klassennamen eingegeben wird, und verwendet sie für Suchvorgänge.

public static CardSuit getIfPresent(String name) {
    return Enums.getIfPresent(CardSuit.class, name).orNull();
}
Nach dem Login kopieren
log.debug("Running Guava getIfPresent");
for (String name : names) {
    log.debug("looking up {} found {}", name, Json.serializer().toString(CardSuit.getIfPresent(name)));
}
Nach dem Login kopieren
2017-02-22 14:46:38.813 [main] DEBUG c.s.examples.common.EnumLookup - Running Guava getIfPresent
2017-02-22 14:46:38.814 [main] DEBUG c.s.examples.common.EnumLookup - looking up SPADE found {"displayName":"Spade","symbol":"♠","color":"BLACK"}
2017-02-22 14:46:38.814 [main] DEBUG c.s.examples.common.EnumLookup - looking up HEART found {"displayName":"Heart","symbol":"♥","color":"RED"}
2017-02-22 14:46:38.815 [main] DEBUG c.s.examples.common.EnumLookup - looking up DIAMOND found {"displayName":"Diamond","symbol":"♦","color":"RED"}
2017-02-22 14:46:38.815 [main] DEBUG c.s.examples.common.EnumLookup - looking up CLUB found {"displayName":"Club","symbol":"♣","color":"BLACK"}
2017-02-22 14:46:38.815 [main] DEBUG c.s.examples.common.EnumLookup - looking up Missing found null
Nach dem Login kopieren
Weitere Indizierung nach Feld

Diese exakt gleiche Methode kann für andere Felder der Enumeration verwendet werden. Es ist nicht ungewöhnlich, eine Aufzählung anhand ihres angezeigten Namens oder anderer Eigenschaften zu finden.

Statische Karte, indexiert nach Feld (besser)

Gleiche Methode wie oben, aber Indizierung anhand des Anzeigenamens anstelle des Enumerationsnamens.

private static final Map<String, CardSuit> displayNameIndex =
        Maps.newHashMapWithExpectedSize(CardSuit.values().length);
static {
    for (CardSuit suit : CardSuit.values()) {
        displayNameIndex.put(suit.getDisplayName(), suit);
    }
}
public static CardSuit lookupByDisplayName(String name) {
    return displayNameIndex.get(name);
}
Nach dem Login kopieren
log.debug("Running lookupByDisplayName");
for (String displayName : displayNames) {
    log.debug("looking up {} found {}", displayName, Json.serializer().toString(CardSuit.lookupByDisplayName(displayName)));
}
Nach dem Login kopieren

2017-02-22 14:46:38.815 [main] DEBUG c.s.examples.common.EnumLookup - Running lookupByDisplayName
2017-02-22 14:46:38.815 [main] DEBUG c.s.examples.common.EnumLookup - looking up Spade found {"displayName":"Spade","symbol":"♠","color":"BLACK"}
2017-02-22 14:46:38.815 [main] DEBUG c.s.examples.common.EnumLookup - looking up Heart found {"displayName":"Heart","symbol":"♥","color":"RED"}
2017-02-22 14:46:38.815 [main] DEBUG c.s.examples.common.EnumLookup - looking up Diamond found {"displayName":"Diamond","symbol":"♦","color":"RED"}
2017-02-22 14:46:38.816 [main] DEBUG c.s.examples.common.EnumLookup - looking up Club found {"displayName":"Club","symbol":"♣","color":"BLACK"}
2017-02-22 14:46:38.816 [main] DEBUG c.s.examples.common.EnumLookup - looking up Missing found null
Nach dem Login kopieren
Statische Karte, indexiert nach Feld (besser)

Wir können Guava hier nicht nutzen, da es schwierig wäre, einen eindeutigen globalen Schlüssel für einen statischen Index zu erstellen. Das heißt aber nicht, dass wir keine Hilfe haben!

public class EnumUtils {
    public static <T, E extends Enum<E>> Function<T, E> lookupMap(Class<E> clazz, Function<E, T> mapper) {
        @SuppressWarnings("unchecked")
        E[] emptyArray = (E[]) Array.newInstance(clazz, 0);
        return lookupMap(EnumSet.allOf(clazz).toArray(emptyArray), mapper);
    }
    public static <T, E extends Enum<E>> Function<T, E> lookupMap(E[] values, Function<E, T> mapper) {
        Map<T, E> index = Maps.newHashMapWithExpectedSize(values.length);
        for (E value : values) {
            index.put(mapper.apply(value), value);
        }
        return (T key) -> index.get(key);
    }
}
Nach dem Login kopieren

Jetzt haben wir eine universelle Lösung, die wenig mit Boilerplate zu tun hat.

private static final Function<String, CardSuit> func =
        EnumUtils.lookupMap(CardSuit.class, e -> e.getDisplayName());
public static CardSuit lookupByDisplayNameUtil(String name) {
    return func.apply(name);
}
Nach dem Login kopieren
log.debug("Running lookupByDisplayNameUtil");
for (String displayName : displayNames) {
    log.debug("looking up {} found {}", displayName, Json.serializer().toString(CardSuit.lookupByDisplayNameUtil(displayName)));
}
Nach dem Login kopieren
2017-02-22 14:46:38.816 [main] DEBUG c.s.examples.common.EnumLookup - Running lookupByDisplayNameUtil
2017-02-22 14:46:38.816 [main] DEBUG c.s.examples.common.EnumLookup - looking up Spade found {"displayName":"Spade","symbol":"♠","color":"BLACK"}
2017-02-22 14:46:38.816 [main] DEBUG c.s.examples.common.EnumLookup - looking up Heart found {"displayName":"Heart","symbol":"♥","color":"RED"}
2017-02-22 14:46:38.816 [main] DEBUG c.s.examples.common.EnumLookup - looking up Diamond found {"displayName":"Diamond","symbol":"♦","color":"RED"}
2017-02-22 14:46:38.816 [main] DEBUG c.s.examples.common.EnumLookup - looking up Club found {"displayName":"Club","symbol":"♣","color":"BLACK"}
2017-02-22 14:46:38.816 [main] DEBUG c.s.examples.common.EnumLookup - looking up Missing found null
Nach dem Login kopieren
Fazit

Hier gibt es mehrere Methoden, mit denen sich das gleiche Problem lösen lässt. Manche sind schlecht, manche sind besser.

Englischer Originaltext: Java-Enum-Suche nach Name oder Feld ohne Auslösen von Ausnahmen

Übersetzungsautor: MaNong.com – Xiaofeng

Das obige ist der detaillierte Inhalt vonVergleich der Vor- und Nachteile mehrerer Java-Enumerations-Lookup-Implementierungen, die keine Ausnahmen auslösen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:linuxprobe.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!