Was sind Aufzählungen und warum sind sie nützlich?

488

Heute habe ich einige Fragen auf dieser Site durchgesehen und eine Erwähnung einer enum Verwendung in Singleton-Mustern über angebliche Vorteile der Thread-Sicherheit für eine solche Lösung gefunden.

Ich habe enums noch nie benutzt und programmiere seit mehr als ein paar Jahren in Java. Und anscheinend haben sie sich sehr verändert. Jetzt unterstützen sie OOP sogar voll und ganz in sich.

Warum und wofür sollte ich nun enum in der täglichen Programmierung verwenden?

Mat B.
quelle
6
In seinem Buch Effective Java, Second Edition , geht Joshua Bloch in Punkt 3 auf diesen Ansatz ein : Erzwingen Sie die Singleton-Eigenschaft mit einem privaten Konstruktor oder einem Aufzählungstyp , der in Dr. Dobbs abgedruckt ist .
Trashgod
mögliches Duplikat von Enum in Java. Vorteile?
Finnw
Sie können Enums nicht instanziieren, da es einen privaten Konstruktor hat. Sie werden beim Start von JVM instanziiert, daher sind Enums für Singleton nicht threadsicher.
Arnav Joshi

Antworten:

633

Sie sollten immer Enums verwenden, wenn eine Variable (insbesondere ein Methodenparameter) nur einen aus einem kleinen Satz möglicher Werte herausnehmen kann. Beispiele wären Typkonstanten (Vertragsstatus: "permanent", "temporär", "Lehrling") oder Flags ("Jetzt ausführen", "Ausführung verschieben").

Wenn Sie Enums anstelle von Ganzzahlen (oder String-Codes) verwenden, erhöhen Sie die Überprüfung der Kompilierungszeit und vermeiden, dass Fehler ungültige Konstanten übergeben, und Sie dokumentieren, welche Werte zulässig sind.

Übrigens kann eine übermäßige Verwendung von Aufzählungen dazu führen, dass Ihre Methoden zu viel bewirken (es ist oft besser, mehrere separate Methoden zu verwenden, als eine Methode, die mehrere Flags verwendet, die ihre Funktionsweise ändern). Wenn Sie jedoch Flags verwenden oder Codes eingeben müssen, Aufzählungen sind der Weg zu gehen.

Was ist als Beispiel besser?

/** Counts number of foobangs.
 * @param type Type of foobangs to count. Can be 1=green foobangs,
 * 2=wrinkled foobangs, 3=sweet foobangs, 0=all types.
 * @return number of foobangs of type
 */
public int countFoobangs(int type)

gegen

/** Types of foobangs. */
public enum FB_TYPE {
 GREEN, WRINKLED, SWEET, 
 /** special type for all types combined */
 ALL;
}

/** Counts number of foobangs.
 * @param type Type of foobangs to count
 * @return number of foobangs of type
 */
public int countFoobangs(FB_TYPE type)

Ein Methodenaufruf wie:

int sweetFoobangCount = countFoobangs(3);

dann wird:

int sweetFoobangCount = countFoobangs(FB_TYPE.SWEET);

Im zweiten Beispiel wird sofort klar, welche Typen zulässig sind, Dokumente und Implementierung können nicht nicht synchronisiert werden, und der Compiler kann dies erzwingen. Auch ein ungültiger Anruf gefällt

int sweetFoobangCount = countFoobangs(99);

ist nicht mehr möglich.

sleske
quelle
41
Wenn Sie Aufzählungen verwenden und eine Kombination von Werten zulassen möchten, verwenden Sie EnumSet. Dies kommt mit allen Arten von netten Helfern, wie öffentlichen statischen endgültigen EnumSet <FB_TYPE> ALL = EnumSet.allOf (FB_TYPE.class);
RobAu
20
Diese Antworten sind diejenigen, die ich bei SO sehr gerne sehe, weil sich jemand wirklich Mühe gegeben hat. Gute Arbeit, ich verstehe jetzt die Aufzählungen!
Dediqated
1
Ich glaube nicht, dass das stimmt you should *always* use enums when a variable can only take one out of a small set of possible values. Die Verwendung konstanter Werte als 'Binärflag' (mit logischer orVerknüpfung) kann für Echtzeitanwendungen nützlich sein, bei denen der Arbeitsspeicher knapp ist.
Elist
@Elist mit Aufzählungen erhöht die Lesbarkeit Ihrer Codes. Wenn Sie zu einem bestimmten Zeitpunkt Konstanten verwenden, wissen Sie oder Ihr Nachfolger nicht, warum sie verwendet werden ...
:)
136

Warum eine Programmiersprachenfunktion verwenden? Der Grund, warum wir überhaupt Sprachen haben, ist für

  1. Programmierer, die Algorithmen effizient und korrekt in einer Form ausdrücken können, die Computer verwenden können.
  2. Maintainer müssen Algorithmen verstehen, die andere geschrieben haben, und Änderungen korrekt vornehmen.

Aufzählungen verbessern sowohl die Wahrscheinlichkeit der Korrektheit als auch die Lesbarkeit, ohne viel Boilerplate zu schreiben. Wenn Sie bereit sind, Boilerplate zu schreiben, können Sie Aufzählungen "simulieren":

public class Color {
    private Color() {} // Prevent others from making colors.
    public static final Color RED = new Color();
    public static final Color AMBER = new Color();
    public static final Color GREEN = new Color();
}

Jetzt können Sie schreiben:

Color trafficLightColor = Color.RED;

Die Kesselplatte oben hat fast den gleichen Effekt wie

public enum Color { RED, AMBER, GREEN };

Beide bieten die gleiche Überprüfungshilfe vom Compiler. Boilerplate ist nur mehr Tippen. Wenn Sie jedoch viel tippen, wird der Programmierer effizienter (siehe 1), sodass sich diese Funktion lohnt.

Es lohnt sich auch aus mindestens einem weiteren Grund:

Anweisungen wechseln

Eine Sache, die Ihnen die static finalobige Aufzählungssimulation nicht bietet , sind schöne switchFälle. Bei Aufzählungstypen verwendet der Java-Switch den Typ seiner Variablen, um den Umfang der Aufzählungsfälle abzuleiten. Für die enum Coloroben genannten Fälle müssen Sie lediglich Folgendes sagen:

Color color = ... ;
switch (color) {
    case RED:
        ...
        break;
}

Beachten Sie, dass dies nicht Color.REDder Fall ist. Wenn Sie keine Aufzählung verwenden, können Sie benannte Mengen nur mit switchfolgenden Methoden verwenden:

public Class Color {
    public static final int RED = 0;
    public static final int AMBER = 1;
    public static final int GREEN = 2;
}

Aber jetzt muss eine Variable, die eine Farbe enthält, einen Typ haben int. Die nette Compilerprüfung der Enumeration und der static finalSimulation ist weg. Nicht glücklich.

Ein Kompromiss besteht darin, ein skalarwertiges Element in der Simulation zu verwenden:

public class Color {
    public static final int RED_TAG = 1;
    public static final int AMBER_TAG = 2;
    public static final int GREEN_TAG = 3;

    public final int tag;

    private Color(int tag) { this.tag = tag; } 
    public static final Color RED = new Color(RED_TAG);
    public static final Color AMBER = new Color(AMBER_TAG);
    public static final Color GREEN = new Color(GREEN_TAG);
}

Jetzt:

Color color = ... ;
switch (color.tag) {
    case Color.RED_TAG:
        ...
        break;
}

Aber beachten Sie, noch mehr Boilerplate!

Verwenden einer Aufzählung als Singleton

Auf der Boilerplate oben können Sie sehen, warum eine Aufzählung eine Möglichkeit bietet, einen Singleton zu implementieren. Anstatt zu schreiben:

public class SingletonClass {
    public static final void INSTANCE = new SingletonClass();
    private SingletonClass() {}

    // all the methods and instance data for the class here
}

und dann mit darauf zugreifen

SingletonClass.INSTANCE

wir können nur sagen

public enum SingletonClass {
    INSTANCE;

    // all the methods and instance data for the class here
}

das gibt uns das gleiche. Wir können damit durchkommen , weil Java Aufzählungen sind als volle Klassen mit nur wenig syntaktischen Zucker über die oberen bestreut umgesetzt. Dies ist wieder weniger Boilerplate, aber es ist nicht offensichtlich, es sei denn, die Redewendung ist Ihnen vertraut. Ich mag auch nicht die Tatsache, dass Sie die verschiedenen Enum-Funktionen erhalten, obwohl sie für den Singleton nicht viel Sinn machen: ordund valuesusw. (Es gibt tatsächlich eine schwierigere Simulation, bei der Color extends Integerdas mit Switch funktioniert, aber es ist so schwierig, dass es noch mehr ist zeigt deutlich warumenum eine bessere Idee ist.)

Gewindesicherheit

Die Thread-Sicherheit ist nur dann ein potenzielles Problem, wenn Singletons ohne Verriegelung träge erstellt werden.

public class SingletonClass {
    private static SingletonClass INSTANCE;
    private SingletonClass() {}
    public SingletonClass getInstance() {
        if (INSTANCE == null) INSTANCE = new SingletonClass();
        return INSTANCE;
    }

    // all the methods and instance data for the class here
}

Wenn viele Threads getInstancegleichzeitig aufrufen, während sie INSTANCEnoch null sind, können beliebig viele Instanzen erstellt werden. Das ist schlecht. Die einzige Lösung besteht darin, synchronizedZugriff hinzuzufügen , um die Variable zu schützen INSTANCE.

Der static finalobige Code weist dieses Problem jedoch nicht auf. Es erstellt die Instanz eifrig zur Ladezeit der Klasse. Das Laden der Klasse wird synchronisiert.

Der enumSingleton ist effektiv faul, da er erst bei der ersten Verwendung initialisiert wird. Die Java-Initialisierung wird ebenfalls synchronisiert, sodass mehrere Threads nicht mehr als eine Instanz von initialisieren können INSTANCE. Sie erhalten einen träge initialisierten Singleton mit sehr wenig Code. Das einzig Negative ist die eher obskure Syntax. Sie müssen die Redewendung kennen oder genau wissen, wie das Laden und Initialisieren von Klassen funktioniert, um zu wissen, was passiert.

Gen
quelle
15
Dieser letzte Absatz hat die Singleton-Situation für mich wirklich klargestellt. Vielen Dank! Jeder Leser, der überfliegt, sollte das noch einmal lesen.
Basil Bourque
Ich habe dies gelesen, stackoverflow.com/questions/16771373/… . Jetzt bin ich verwirrt mit deinem letzten Absatz. Wie bietet enum keine Laieninitialisierungsfunktion?
Deepankar Singh
static finalFelder werden zur Klasseninitialisierungszeit initialisiert , nicht zur Ladezeit. Es ist genau das gleiche wie bei einer enumkonstanten Initialisierung (tatsächlich sind sie unter der Haube identisch). Deshalb war der Versuch, „cleveren“ Lazy-Initialisierungscode für Singletons zu implementieren, selbst in der ersten Java-Version immer sinnlos.
Holger
42

Neben den bereits erwähnten Anwendungsfällen finde ich häufig Aufzählungen nützlich, um das Strategiemuster nach einigen grundlegenden OOP-Richtlinien zu implementieren:

  1. Den Code haben, in dem sich die Daten befinden (dh innerhalb der Aufzählung selbst - oder häufig innerhalb der Aufzählungskonstanten, die Methoden überschreiben können).
  2. Implementieren einer Schnittstelle (oder mehrerer), um den Clientcode nicht an die Aufzählung zu binden (die nur eine Reihe von Standardimplementierungen bereitstellen sollte).

Das einfachste Beispiel wäre eine Reihe von ComparatorImplementierungen:

enum StringComparator implements Comparator<String> {
    NATURAL {
        @Override
        public int compare(String s1, String s2) {
            return s1.compareTo(s2);
        }
    },
    REVERSE {
        @Override
        public int compare(String s1, String s2) {
            return NATURAL.compare(s2, s1);
        }
    },
    LENGTH {
        @Override
        public int compare(String s1, String s2) {
            return new Integer(s1.length()).compareTo(s2.length());
        }
    };
}

Dieses "Muster" kann in weitaus komplexeren Szenarien verwendet werden, wobei alle mit der Aufzählung gelieferten Extras umfassend genutzt werden: Durchlaufen der Instanzen, Verlassen auf ihre implizite Reihenfolge, Abrufen einer Instanz anhand ihres Namens, statische Methoden, die die richtige Instanz bereitstellen für bestimmte Kontexte usw. Und dennoch haben Sie dies alles hinter der Benutzeroberfläche versteckt, sodass Ihr Code mit benutzerdefinierten Implementierungen ohne Änderung funktioniert, falls Sie etwas möchten, das unter den "Standardoptionen" nicht verfügbar ist.

Ich habe gesehen, dass dies erfolgreich für die Modellierung des Konzepts der Zeitgranularität (täglich, wöchentlich usw.) angewendet wurde, bei der die gesamte Logik in einer Aufzählung zusammengefasst war (Auswahl der richtigen Granularität für einen bestimmten Zeitbereich, spezifisches Verhalten, das an jede Granularität als konstant gebunden ist Methoden etc.). Und dennoch war das Granularityaus Sicht der Service-Schicht einfach eine Schnittstelle.

Costi Ciudatu
quelle
2
Sie könnten auch hinzufügen CASE_INSENSITIVE { @Override public int compare(String s1, String s2) { return s1.compareToIgnoreCase(s2); }. Ein noch nicht erwähnter Vorteil besteht darin, dass Sie eine robuste Serialisierungsunterstützung erhalten. Das persistente Formular enthält nur den Klassennamen und den Konstantennamen, unabhängig von den Implementierungsdetails Ihrer Komparatoren.
Holger
32

Keine der anderen Antworten, die Aufzählungen besonders leistungsfähig machen, ist die Möglichkeit, Vorlagenmethoden zu verwenden . Methoden können Teil der Basisaufzählung sein und von jedem Typ überschrieben werden. Und mit dem Verhalten, das mit der Aufzählung verbunden ist, entfällt häufig die Notwendigkeit von if-else-Konstrukten oder switch-Anweisungen, wie dieser Blog-Beitrag zeigt - wo enum.method()wird das ausgeführt, was ursprünglich innerhalb der Bedingung ausgeführt wurde. Das gleiche Beispiel zeigt auch die Verwendung von statischen Importen mit Aufzählungen und erzeugt viel saubereren DSL-ähnlichen Code.

Einige andere interessante Eigenschaften umfassen die Tatsache , dass Aufzählungen bieten Implementierung für equals(), toString()und hashCode()und implementieren Serializableund Comparable.

Für einen vollständigen Überblick über alles, was Enums zu bieten haben, empfehle ich Bruce Eckels Thinking in Java 4th Edition, die dem Thema ein ganzes Kapitel widmet. Besonders aufschlussreich sind die Beispiele für ein Spiel mit Rock, Paper, Scissors (dh RoShamBo) als Enums.

Orangepips
quelle
23

Aus Java- Dokumenten -

Sie sollten Aufzählungstypen immer dann verwenden, wenn Sie einen festen Satz von Konstanten darstellen müssen. Dazu gehören natürliche Aufzählungstypen wie die Planeten in unserem Sonnensystem und Datensätze, in denen Sie alle möglichen Werte zur Kompilierungszeit kennen, z. B. die Auswahlmöglichkeiten in einem Menü, Befehlszeilenflags usw.

Ein häufiges Beispiel ist das Ersetzen einer Klasse durch eine Reihe privater statischer endgültiger int-Konstanten (innerhalb einer angemessenen Anzahl von Konstanten) durch einen Aufzählungstyp. Wenn Sie glauben, alle möglichen Werte von "etwas" zur Kompilierungszeit zu kennen, können Sie dies als Aufzählungstyp darstellen. Aufzählungen bieten Lesbarkeit und Flexibilität gegenüber einer Klasse mit Konstanten.

Einige andere Vorteile, die ich mir für Aufzählungstypen vorstellen kann. Sie sind immer eine Instanz einer bestimmten Enum-Klasse (daher kommt das Konzept, Enums als Singleton zu verwenden). Ein weiterer Vorteil ist, dass Sie Aufzählungen als Typ in der switch-case-Anweisung verwenden können. Sie können auch toString () in der Enumeration verwenden, um sie als lesbare Zeichenfolgen zu drucken.

Kühle Bohnen
quelle
8
Würden Sie für alle 366 Tage im Jahr eine Aufzählung verwenden? Es ist eine feste Menge (366) von Konstanten (die Tage ändern sich nicht). Das schlägt also vor, dass Sie sollten. : - / Ich würde die Größe des festen Satzes einschränken.
Moinudin
2
@marcog Mit ein wenig klugem Denken könnte es möglich sein, Wochentage und Tage in jedem Monat in einer kompakten Aufzählung zusammenzufassen.
James P.
1
Apropos Wochentage… DayOfWeekenum ist jetzt vordefiniert, in Java 8 und höher als Teil des java.time- Frameworks integriert (und auf Java 6 & 7 und Android zurückportiert ).
Basil Bourque
19

Warum und wofür sollte ich Enum in der täglichen Programmierung verwenden?

Sie können eine Aufzählung verwenden, um einen kleineren festen Satz von Konstanten oder einen internen Klassenmodus darzustellen und gleichzeitig die Lesbarkeit zu verbessern. Enums können auch eine bestimmte Starrheit erzwingen, wenn sie in Methodenparametern verwendet werden. Sie bieten die interessante Möglichkeit, Informationen an einen Konstruktor wie im Planets-Beispiel auf der Oracle-Site zu übergeben, und ermöglichen, wie Sie festgestellt haben, auch eine einfache Möglichkeit, ein Singleton-Muster zu erstellen.

Beispiel: Locale.setDefault(Locale.US)Liest besser als Locale.setDefault(1)und erzwingt die Verwendung des festen Wertesatzes, der in einer IDE angezeigt wird, wenn Sie das .Trennzeichen anstelle aller Ganzzahlen hinzufügen .

James P.
quelle
@arnt Ich habe die Grammatik in der Frage auch korrigiert. Vielen Dank.
James P.
13

Enums Auflisten eines festen Satzes von Werten auf selbstdokumentierende Weise.
Sie machen Ihren Code expliziter und weniger fehleranfällig.

Warum nicht Stringoder intstatt EnumKonstanten verwenden?

  1. Der Compiler erlaubt keine Tippfehler und auch keine Werte aus dem festen Satz, da Aufzählungen Typen für sich sind. Konsequenzen:
    • Sie müssen keine Vorbedingung (oder ein Handbuch if) schreiben , um sicherzustellen, dass Ihr Argument im gültigen Bereich liegt.
    • Die Typinvariante ist kostenlos.
  2. Aufzählungen können sich wie jede andere Klasse verhalten.
  3. Sie würden wahrscheinlich Stringsowieso eine ähnliche Menge an Speicher benötigen, um s zu verwenden (dies hängt von der Komplexität des ab Enum).

Darüber hinaus ist jede EnumInstanz der Klasse eine Klasse, für die Sie ihr individuelles Verhalten definieren können.

Außerdem gewährleisten sie die Thread-Sicherheit beim Erstellen der Instanzen (wenn die Aufzählung geladen wird), was bei der Vereinfachung des Singleton-Musters eine große Anwendung gefunden hat .

Dieser Blog zeigt einige seiner Anwendungen, z. B. eine Zustandsmaschine für einen Parser.

afsantos
quelle
13

Es ist nützlich zu wissen, dass enumsgenau wie die anderen Klassen mit ConstantFeldern und a private constructor.

Zum Beispiel,

public enum Weekday
{
  MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
} 

Der Compiler kompiliert es wie folgt;

class Weekday extends Enum
{
  public static final Weekday MONDAY  = new Weekday( "MONDAY",   0 );
  public static final Weekday TUESDAY = new Weekday( "TUESDAY ", 1 );
  public static final Weekday WEDNESDAY= new Weekday( "WEDNESDAY", 2 );
  public static final Weekday THURSDAY= new Weekday( "THURSDAY", 3 );
  public static final Weekday FRIDAY= new Weekday( "FRIDAY", 4 );
  public static final Weekday SATURDAY= new Weekday( "SATURDAY", 5 );
  public static final Weekday SUNDAY= new Weekday( "SUNDAY", 6 );

  private Weekday( String s, int i )
  {
    super( s, i );
  }

  // other methods...
}
Ad infinitum
quelle
12

enumbedeutet Aufzählung, dh Erwähnung (einer Reihe von Dingen) nacheinander.

Eine Aufzählung ist ein Datentyp, der einen festen Satz von Konstanten enthält.

ODER

An enumist genau wie a class, mit einer festen Anzahl von Instanzen, die zur Kompilierungszeit bekannt sind.

Zum Beispiel:

public class EnumExample {
    interface SeasonInt {
        String seasonDuration();
    }

    private enum Season implements SeasonInt {
        // except the enum constants remaining code looks same as class
        // enum constants are implicitly public static final we have used all caps to specify them like Constants in Java
        WINTER(88, "DEC - FEB"), SPRING(92, "MAR - JUN"), SUMMER(91, "JUN - AUG"), FALL(90, "SEP - NOV");

        private int days;
        private String months;

        Season(int days, String months) { // note: constructor is by default private 
            this.days = days;
            this.months = months;
        }

        @Override
        public String seasonDuration() {
            return this+" -> "+this.days + "days,   " + this.months+" months";
        }

    }
    public static void main(String[] args) {
        System.out.println(Season.SPRING.seasonDuration());
        for (Season season : Season.values()){
            System.out.println(season.seasonDuration());
        }

    }
}

Vorteile von Enum:

  • enum verbessert die Typensicherheit bei der Überprüfung zur Kompilierungszeit, um Fehler zur Laufzeit zu vermeiden.
  • enum kann leicht in switch verwendet werden
  • Aufzählung kann durchlaufen werden
  • enum kann Felder, Konstruktoren und Methoden haben
  • enum kann viele Schnittstellen implementieren, aber keine Klasse erweitern, da es die Enum-Klasse intern erweitert

für mehr

Premraj
quelle
9

Was ist eine Aufzählung?

  • enum ist ein Schlüsselwort, das für die Aufzählung eines neuen Datentyps definiert ist. Typensichere Aufzählungen sollten großzügig verwendet werden. Insbesondere sind sie eine robuste Alternative zu den einfachen String- oder int-Konstanten, die in viel älteren APIs verwendet werden, um Sätze verwandter Elemente darzustellen.

Warum enum verwenden

  • Aufzählungen sind implizit letzte Unterklassen von java.lang.Enum
  • Wenn eine Aufzählung Mitglied einer Klasse ist, ist sie implizit statisch
  • new kann niemals mit einer Aufzählung verwendet werden, auch nicht innerhalb des Aufzählungstyps
  • name und valueOf verwenden Sie einfach den Text der Enum-Konstanten, während toString bei Bedarf überschrieben werden kann, um Inhalte bereitzustellen
  • Für Enum-Konstanten sind gleich und == gleich und können austauschbar verwendet werden
  • Enum-Konstanten sind implizit öffentlich statisch final

Hinweis

  • Aufzählungen können keine Klasse erweitern.
  • Eine Aufzählung kann keine Oberklasse sein.
  • Die Reihenfolge des Auftretens von Enum-Konstanten wird als "natürliche Reihenfolge" bezeichnet und definiert die Reihenfolge, die auch von anderen Elementen verwendet wird: compareTo, Iterationsreihenfolge von Werten, EnumSet, EnumSet.range.
  • Eine Aufzählung kann Konstruktoren, statische und Instanzblöcke, Variablen und Methoden enthalten, jedoch keine abstrakten Methoden.
tinker_fairy
quelle
4
Sie erklären nicht, warum Sie Aufzählungen verwenden. Sie listen nur einige Eigenschaften von Aufzählungen unter nicht verwandten Überschriften auf.
Duncan Jones
@ DuncanJones geben die Begriffe final, static nicht den Zweck der Verwendung von Enums an?
Tinker_Fairy
8

Abgesehen von allem, was von anderen gesagt wurde. In einem älteren Projekt, für das ich früher gearbeitet habe, wurden bei der Kommunikation zwischen Entitäten (unabhängigen Anwendungen) ganze Zahlen verwendet, die eine kleine Menge darstellten. Es war nützlich, die Menge wie enumbei statischen Methoden zu deklarieren , um enumObjekte von valueund umgekehrt abzurufen. Der Code sah sauberer aus, wechselte die Benutzerfreundlichkeit der Groß- und Kleinschreibung und erleichterte das Schreiben in Protokolle.

enum ProtocolType {
    TCP_IP (1, "Transmission Control Protocol"), 
    IP (2, "Internet Protocol"), 
    UDP (3, "User Datagram Protocol");

    public int code;
    public String name;

    private ProtocolType(int code, String name) {
        this.code = code;
        this.name = name;
    }

    public static ProtocolType fromInt(int code) {
    switch(code) {
    case 1:
        return TCP_IP;
    case 2:
        return IP;
    case 3:
        return UDP;
    }

    // we had some exception handling for this
    // as the contract for these was between 2 independent applications
    // liable to change between versions (mostly adding new stuff)
    // but keeping it simple here.
    return null;
    }
}

Erstellen Sie ein enumObjekt aus empfangenen Werten (z. B. 1,2) mit ProtocolType.fromInt(2) Write to Logs mitmyEnumObj.name

Hoffe das hilft.

sErVerdevIL
quelle
6

Enum erbt alle Methoden der ObjectKlasse und der abstrakten KlasseEnum . Sie können also die Methoden für Reflexion, Multithreading, Serilisierung usw. verwenden. Wenn Sie anstelle von Enum nur eine statische Konstante deklarieren, können Sie dies nicht. Außerdem kann der Wert von Enum auch an die DAO-Ebene übergeben werden.

Hier ist ein Beispielprogramm zur Demonstration.

public enum State {

    Start("1"),
    Wait("1"),
    Notify("2"),
    NotifyAll("3"),
    Run("4"),
    SystemInatilize("5"),
    VendorInatilize("6"),
    test,
    FrameworkInatilize("7");

    public static State getState(String value) {
        return State.Wait;
    }

    private String value;
    State test;

    private State(String value) {
        this.value = value;
    }

    private State() {
    }

    public String getValue() {
        return value;
    }

    public void setCurrentState(State currentState) {
        test = currentState;
    }

    public boolean isNotify() {
        return this.equals(Notify);
    }
}

public class EnumTest {

    State test;

    public void setCurrentState(State currentState) {
        test = currentState;
    }

    public State getCurrentState() {
        return test;
    }

    public static void main(String[] args) {
        System.out.println(State.test);
        System.out.println(State.FrameworkInatilize);
        EnumTest test=new EnumTest();
        test.setCurrentState(State.Notify);
        test. stateSwitch();
    }

    public void stateSwitch() {
        switch (getCurrentState()) {
        case Notify:
            System.out.println("Notify");
            System.out.println(test.isNotify());
            break;
        default:
            break;
        }
    }
}
Abishkar Bhattarai
quelle
4

ENum steht für "Enumerated Type". Es ist ein Datentyp mit einem festen Satz von Konstanten, die Sie selbst definieren.

Steve
quelle
Sie haben nicht erklärt, warum Sie eine Aufzählung verwenden sollen.
Duncan Jones
4
Ja, habe ich. Sie speichern damit einen festen Satz von Konstanten, die Sie selbst definieren. Die konkrete Anwendung liegt bei Ihnen. Es gibt keine Möglichkeit zu sagen, wann, warum oder wie man etwas benutzt. Das liegt an den Bedürfnissen des Entwicklers. Sie müssen nur verstehen, was es ist und wie es funktioniert.
Steve
4

Meiner Meinung nach sind alle Antworten, die Sie bisher erhalten haben, gültig, aber meiner Erfahrung nach würde ich es in wenigen Worten ausdrücken:

Verwenden Sie Aufzählungen, wenn der Compiler die Gültigkeit des Werts eines Bezeichners überprüfen soll.

Andernfalls können Sie Zeichenfolgen wie immer verwenden (wahrscheinlich haben Sie einige "Konventionen" für Ihre Anwendung definiert) und Sie werden sehr flexibel sein ... aber Sie erhalten keine 100% ige Sicherheit gegen Tippfehler auf Ihren Zeichenfolgen und Sie werden sie nur realisieren zur Laufzeit.

Rafa
quelle
3

Verwenden Sie Enums für TYPE SAFETY. Dies ist eine Sprachfunktion, die Sie normalerweise erhalten:

  • Compiler-Unterstützung (siehe sofort Typprobleme)
  • Tool-Unterstützung in IDEs (automatische Vervollständigung im Switch-Fall, fehlende Fälle, Standard erzwingen, ...)
  • In einigen Fällen ist die Enum-Leistung ebenfalls großartig ( EnumSet , eine typsichere Alternative zu herkömmlichen int-basierten "Bit-Flags" ).

Aufzählungen können Methoden und Konstruktoren enthalten. Sie können sogar Aufzählungen in Aufzählungen verwenden und Aufzählungen mit Schnittstellen kombinieren.

Stellen Sie sich Enums als Typen vor, die einen genau definierten Satz von int-Konstanten ersetzen (die Java von C / C ++ 'geerbt' hat) und in einigen Fällen Bit-Flags ersetzen.

Das Buch Effective Java 2nd Edition enthält ein ganzes Kapitel und geht auf weitere Details ein. Siehe auch diesen Beitrag zum Stapelüberlauf .

Christophe Roussy
quelle
2

Mit Java können Sie Variablen auf einen von nur wenigen vordefinierten Werten beschränken - mit anderen Worten, einen Wert aus einer Aufzählungsliste. Die Verwendung enumskann dazu beitragen, Fehler in Ihrem Code zu reduzieren. Hier ist ein Beispiel enumsaußerhalb einer Klasse:

enums coffeesize{BIG , HUGE , OVERWHELMING }; 
//This semicolon is optional.

Dies beschränkt coffeesizeauf, die entweder: BIG, HUGEoder OVERWHELMINGals eine Variable.

Rahul Prajapat
quelle
2

Aufzählung? Warum sollte es verwendet werden? Ich denke, es ist verständlicher, wann Sie es verwenden werden. Ich habe die gleiche Erfahrung.

Angenommen, Sie haben eine Datenbankoperation zum Erstellen, Löschen, Bearbeiten und Lesen.

Wenn Sie nun eine Aufzählung als Operation erstellen:

public enum operation {
    create("1")
    delete("2")
    edit("3")
    read("4")

    // You may have is methods here
    public boolean isCreate() {
        return this.equals(create);
    }
    // More methods like the above can be written

}

Jetzt können Sie etwas deklarieren wie:

private operation currentOperation;

// And assign the value for it 
currentOperation = operation.create

Sie können es also auf viele Arten verwenden. Es ist immer gut, eine Aufzählung für bestimmte Dinge zu haben, da die Datenbankoperation im obigen Beispiel durch Überprüfen der aktuellen Operation gesteuert werden kann . Vielleicht kann man sagen, dass dies auch mit Variablen und ganzzahligen Werten erreicht werden kann. Aber ich glaube, Enum ist sicherer und ein Programmierer.

Eine andere Sache: Ich denke, jeder Programmierer liebt Boolesche Werte , nicht wahr? Da nur zwei Werte gespeichert werden können, zwei spezifische Werte. Man kann sich also vorstellen, dass Enum dieselbe Art von Einrichtungen hat, in denen ein Benutzer definiert, wie viele und welche Art von Wert er speichert, nur auf etwas andere Weise. :) :)

Abhishek Bhandari
quelle
1

Bisher musste ich nie Aufzählungen verwenden. Ich habe darüber gelesen, seit sie in Version 1.5 oder Version Tiger eingeführt wurden, wie es damals genannt wurde. Sie haben nie wirklich ein "Problem" für mich gelöst. Für diejenigen, die es benutzen (und ich sehe viele von ihnen), bin ich sicher, dass es definitiv einen Zweck erfüllt. Nur meine 2 Pfund.

happybuddha
quelle
1

Was mir den Ah-Ha-Moment gab, war diese Erkenntnis: dass Enum einen privaten Konstruktor hat, der nur über die öffentliche Aufzählung zugänglich ist:

enum RGB {
    RED("Red"), GREEN("Green"), BLUE("Blue");

    public static final String PREFIX = "color ";

    public String getRGBString() {
        return PREFIX + color;
    }

    String color;

    RGB(String color) {
        this.color = color;
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        String c = RGB.RED.getRGBString();
        System.out.print("Hello " + c);
    }
}
Djangofan
quelle
1

Um den Code in Zukunft lesbar zu machen, wird der nützlichste anwendbare Fall der Aufzählung im nächsten Snippet dargestellt:

public enum Items {
    MESSAGES, CHATS, CITY_ONLINE, FRIENDS, PROFILE, SETTINGS, PEOPLE_SEARCH, CREATE_CHAT
}

@Override
public boolean onCreateOptionsMenu(Menu menuPrm) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menuPrm);
    View itemChooserLcl;
    for (int i = 0; i < menuPrm.size(); i++) {
        MenuItem itemLcl  = menuPrm.getItem(i);
            itemChooserLcl = itemLcl.getActionView();
            if (itemChooserLcl != null) {
                 //here Im marking each View' tag by enume values:
                itemChooserLcl.setTag(Items.values()[i]);
                itemChooserLcl.setOnClickListener(drawerMenuListener);
            }
        }
    return true;
}
private View.OnClickListener drawerMenuListener=new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Items tagLcl= (Items) v.getTag();
        switch (tagLcl){
            case MESSAGES: ;
            break;
            case CHATS : ;
            break;
            case CITY_ONLINE : ;
            break;
            case FRIENDS : ;
            break;
            case  PROFILE: ;
            break;
            case  SETTINGS: ;
            break;
            case  PEOPLE_SEARCH: ;
            break;
            case  CREATE_CHAT: ;
            break;
        }
    }
};
CodeToLife
quelle
1

Nach meiner Erfahrung hat die Verwendung von Enum manchmal dazu geführt, dass es sehr schwierig ist, Systeme zu ändern. Wenn Sie eine Aufzählung für eine Reihe domänenspezifischer Werte verwenden, die sich häufig ändern, und viele andere Klassen und Komponenten davon abhängen, sollten Sie in Betracht ziehen, keine Aufzählung zu verwenden.

Zum Beispiel ein Handelssystem, das eine Aufzählung für Märkte / Börsen verwendet. Es gibt viele Märkte und es ist fast sicher, dass es viele Subsysteme geben wird, die auf diese Liste von Märkten zugreifen müssen. Jedes Mal, wenn Sie möchten, dass Ihrem System ein neuer Markt hinzugefügt wird, oder wenn Sie einen Markt entfernen möchten, muss möglicherweise alles unter der Sonne neu aufgebaut und freigegeben werden.

Ein besseres Beispiel wäre so etwas wie ein Produktkategorietyp. Angenommen, Ihre Software verwaltet das Inventar eines Kaufhauses. Es gibt viele Produktkategorien und viele Gründe, warum sich diese Liste von Kategorien ändern könnte. Manager möchten möglicherweise eine neue Produktlinie auf Lager haben, andere Produktlinien entfernen und möglicherweise die Kategorien von Zeit zu Zeit neu organisieren. Wenn Sie alle Ihre Systeme neu erstellen und erneut bereitstellen müssen, nur weil Benutzer eine Produktkategorie hinzufügen möchten, haben Sie etwas gewählt, das einfach und schnell sein sollte (Hinzufügen einer Kategorie), und es sehr schwierig und langsam gemacht.

Unterm Strich sind Aufzählungen gut, wenn die von Ihnen dargestellten Daten im Laufe der Zeit sehr statisch sind und eine begrenzte Anzahl von Abhängigkeiten aufweisen. Wenn sich die Daten jedoch stark ändern und viele Abhängigkeiten aufweisen, benötigen Sie etwas Dynamisches, das beim Kompilieren nicht überprüft wird (z. B. eine Datenbanktabelle).

BradB
quelle
1

Der auf Enum basierende Singleton

ein moderner Blick auf ein altes Problem

Dieser Ansatz implementiert den Singleton, indem er die Garantie von Java nutzt, dass ein Enum-Wert in einem Java-Programm nur einmal instanziiert wird und Enum implizite Unterstützung für die Thread-Sicherheit bietet. Da auf Java-Enum-Werte global zugegriffen werden kann, kann sie als Singleton verwendet werden.

public enum Singleton {
    SINGLETON; 
    public void method() { }
}

Wie funktioniert das? Nun, die zweite Zeile des Codes kann wie folgt betrachtet werden:

public final static Singleton SINGLETON = new Singleton(); 

Und wir bekommen einen guten alten, früh initialisierten Singleton.

Denken Sie daran, dass Sie, da dies eine Aufzählung ist, immer auch über auf die Instanz zugreifen können Singleton.INSTANCE:

Singleton s = Singleton.INSTANCE;
Vorteile
  • Um zu verhindern, dass während der Deserialisierung weitere Singleton-Instanzen erstellt werden, verwenden Sie Enum-basiertes Singleton, da die Serialisierung von Enum von JVM übernommen wird. Enum-Serialisierung und -Deserialisierung funktionieren anders als bei normalen Java-Objekten. Das einzige, was serialisiert wird, ist der Name des Aufzählungswerts. Während des Deserialisierungsprozesses wird die AufzählungvalueOf Methode mit dem deserialisierten Namen verwendet, um die gewünschte Instanz zu erhalten.
  • Enum-basierter Singleton ermöglicht es, sich vor Reflexionsangriffen zu schützen. Der Aufzählungstyp erweitert tatsächlich die Java- EnumKlasse. Der Grund dafür, dass Reflektion nicht zum Instanziieren von Objekten vom Aufzählungstyp verwendet werden kann, liegt darin, dass die Java-Spezifikation dies nicht zulässt und diese Regel in der Implementierung der newInstanceMethode der ConstructorKlasse codiert ist , die normalerweise zum Erstellen von Objekten über Reflektion verwendet wird:
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
    throw new IllegalArgumentException("Cannot reflectively create enum objects");
  • Enum sollte nicht geklont werden, da es für jeden Wert genau eine Instanz geben muss.
  • Der lakonischste Code unter allen Singleton-Realisierungen.
Nachteile
  • Der auf Enum basierende Singleton erlaubt keine verzögerte Initialisierung.
  • Wenn Sie Ihr Design geändert haben und Ihren Singleton in Multiton konvertieren möchten, würde enum dies nicht zulassen. Das Multiton-Muster wird für die kontrollierte Erstellung mehrerer Instanzen verwendet, die mithilfe von a verwaltet werden map. Anstatt eine einzelne Instanz pro Anwendung (z. B. die java.lang.Runtime) zu haben, stellt das Multiton-Muster stattdessen eine einzelne Instanz pro Schlüssel sicher .
  • Enum wird nur in Java 5 angezeigt, sodass Sie es in früheren Versionen nicht verwenden können.

Es gibt mehrere Realisierungen von Singleton-Mustern mit jeweils Vor- und Nachteilen.

  • Eifriges Laden von Singleton
  • Doppelter Sperr-Singleton
  • Initialisierung-on-Demand-Inhabersprache
  • Der auf Enum basierende Singleton

Detaillierte Beschreibung Jeder von ihnen ist zu ausführlich, deshalb habe ich nur einen Link zu einem guten Artikel eingefügt - Alles, was Sie über Singleton wissen wollen

Oleg Poltoratskii
quelle
0

Ich würde Enums als nützliches Mapping-Instrument verwenden und mehrere vermeiden, if-else vorausgesetzt, einige Methoden sind implementiert.

public enum Mapping {

    ONE("1"),
    TWO("2");

    private String label;

    private Mapping(String label){
        this.label = label;
    }

    public static Mapping by(String label) {

        for(Mapping m: values() {
            if(m.label.equals(label)) return m;
        }

        return null;
    }

}

Mit dieser Methode by(String label)können Sie den Aufzählungswert also durch Nichtaufzählung abrufen. Ferner kann man eine Zuordnung zwischen 2 Aufzählungen erfinden. Könnte auch '1 zu viele' oder 'viele zu viele' zusätzlich zu 'eins zu eins' Standardbeziehung versuchen

Am Ende enumist eine Java-Klasse. Sie können also eine mainMethode darin haben, die nützlich sein kann, wenn Sie einige Zuordnungsvorgänge argssofort ausführen müssen .

TEH EMPRAH
quelle
0

Anstatt eine Reihe von const int-Deklarationen abzugeben

Sie können sie alle in einer Aufzählung gruppieren

Es ist also alles von der gemeinsamen Gruppe organisiert, zu der sie gehören

Vincent Tang
quelle
0

Aufzählungen sind wie Klassen. Wie die Klasse hat es auch Methoden und Attribute.

Unterschiede zur Klasse sind: 1. Enum-Konstanten sind öffentlich, statisch, endgültig. 2. Eine Aufzählung kann nicht zum Erstellen eines Objekts verwendet werden und kann keine anderen Klassen erweitern. Es können jedoch Schnittstellen implementiert werden.

Shetu
quelle
0

Zusätzlich zu @BradB Antwort:

Das ist so wahr ... Es ist seltsam, dass es die einzige Antwort ist, die das erwähnt. Wenn Anfänger Enums entdecken, nehmen sie dies schnell als Zaubertrick für die Überprüfung gültiger Bezeichner für den Compiler. Und wenn der Code auf verteilten Systemen verwendet werden soll, weinen sie ... einige Monate später. Die Aufrechterhaltung der Abwärtskompatibilität mit Aufzählungen, die eine nicht statische Werteliste enthalten, ist ein echtes Problem und schmerzhaft. Dies liegt daran, dass sich beim Hinzufügen eines Werts zu einer vorhandenen Aufzählung der Typ ändert (trotz des Namens nicht).

"Ho, warte, es könnte wie der gleiche Typ aussehen, oder? Immerhin handelt es sich um Aufzählungen mit demselben Namen - und sind Aufzählungen nicht nur ganze Zahlen unter der Haube?" Aus diesen Gründen wird Ihr Compiler wahrscheinlich nicht die Verwendung einer Definition des Typs selbst kennzeichnen, bei dem er die andere erwartet hat. Tatsächlich handelt es sich jedoch (in den wichtigsten Punkten) um verschiedene Typen. Am wichtigsten ist, dass sie unterschiedliche Datendomänen haben - Werte, die je nach Typ akzeptabel sind. Durch Hinzufügen eines Werts haben wir den Typ der Aufzählung effektiv geändert und damit die Abwärtskompatibilität unterbrochen.

Fazit: Verwenden Sie es, wenn Sie möchten, überprüfen Sie jedoch, ob es sich bei der verwendeten Datendomäne um eine endliche, bereits bekannte, feste Menge handelt .

Nicolas Voron
quelle