Zoeken…


Invoering

Java-enums (gedeclareerd met behulp van het enum trefwoord) zijn steno-syntaxis voor aanzienlijke hoeveelheden constanten van een enkele klasse.

Syntaxis

  • [public / protected / private] enum Enum_name {// Declareer een nieuw enum.
  • ENUM_CONSTANT_1 [, ENUM_CONSTANT_2 ...]; // Verklaar de enum-constanten. Dit moet de eerste regel binnen het opsommingsteken zijn en moet worden gescheiden door komma's, met een puntkomma aan het einde.
  • ENUM_CONSTANT_1 (param) [, ENUM_CONSTANT_2 (param) ...]; // Vermeld enum-constanten met parameters. De parametertypen moeten overeenkomen met de constructor.
  • ENUM_CONSTANT_1 {...} [, ENUM_CONSTANT_2 {...} ...]; // Vermeld enum-constanten met overschreven methoden. Dit moet worden gedaan als het opsomming abstracte methoden bevat; al dergelijke methoden moeten worden geïmplementeerd.
  • ENUM_CONSTANT.name () // Retourneert een tekenreeks met de naam van de enum-constante.
  • ENUM_CONSTANT.ordinal () // Retourneert de rangtelwoord van deze opsommingsconstante, zijn positie in de opsommingsdeclaratie, waarbij aan de beginconstante een rangtelwoord van nul wordt toegewezen.
  • Enum_name.values () // Retourneert een nieuwe array (van het type Enum_name []) die elke constante van dat enum bevat telkens wanneer deze wordt aangeroepen.
  • Enum_name.valueOf ("ENUM_CONSTANT") // De inverse van ENUM_CONSTANT.name () - retourneert de enum-constante met de opgegeven naam.
  • Enum.valueOf (Enum_name.class, "ENUM_CONSTANT") // Een synoniem van de vorige: Het omgekeerde van ENUM_CONSTANT.name () - retourneert de enum-constante met de opgegeven naam.

Opmerkingen

beperkingen

Enums breiden java.lang.Enum altijd uit, dus het is onmogelijk voor een enum om een klasse uit te breiden. Ze kunnen echter veel interfaces implementeren.

tips & trucs

Vanwege hun gespecialiseerde weergave zijn er efficiëntere kaarten en sets die kunnen worden gebruikt met enums als sleutels. Deze zullen vaak sneller werken dan hun niet-gespecialiseerde tegenhangers.

Verklaar en gebruik een basisoverzicht

Enum kan worden beschouwd als syntaxisuiker voor een verzegelde klasse die slechts een aantal keren bij het compileren bekend wordt gemaakt om een set constanten te definiëren.

Een eenvoudig overzicht van de verschillende seizoenen zou als volgt worden verklaard:

public enum Season {
    WINTER,
    SPRING,
    SUMMER,
    FALL
}

Hoewel de enum-constanten niet noodzakelijk in hoofdletters hoeven te staan, is het volgens de Java-conventie dat namen van constanten volledig uit hoofdletters bestaan, met woorden gescheiden door onderstrepingstekens.


U kunt een Enum in zijn eigen bestand declareren:

/**
 * This enum is declared in the Season.java file.
*/
public enum Season {
    WINTER,
    SPRING,
    SUMMER,
    FALL
}

Maar je kunt het ook binnen een andere klasse verklaren:

 public class Day {

    private Season season;

    public String getSeason() {
        return season.name();
    }

    public void setSeason(String season) {
        this.season = Season.valueOf(season);
    }

    /**
     * This enum is declared inside the Day.java file and 
     * cannot be accessed outside because it's declared as private.
     */
    private enum Season {
        WINTER,
        SPRING,
        SUMMER,
        FALL
    }

}

Ten slotte kunt u een Enum niet declareren in een body of constructor van een methode:

public class Day {

    /**
     * Constructor
    */
    public Day() {
        // Illegal. Compilation error
        enum Season {
            WINTER,
            SPRING,
            SUMMER,
            FALL
        }
    }

    public void aSimpleMethod() {
        // Legal. You can declare a primitive (or an Object) inside a method. Compile!
        int primitiveInt = 42;

        // Illegal. Compilation error.
        enum Season {
            WINTER,
            SPRING,
            SUMMER,
            FALL
        }

        Season season = Season.SPRING;
    }
    
}

Dubbele enum-constanten zijn niet toegestaan:

public enum Season {
    WINTER,
    WINTER, //Compile Time Error : Duplicate Constants
    SPRING,
    SUMMER,
    FALL
} 

Elke constante van Enum is standaard public , static en final . Omdat elke constante static , zijn ze rechtstreeks toegankelijk met de enum-naam.

Enum-constanten kunnen worden doorgegeven als methodeparameters:

public static void display(Season s) {
    System.out.println(s.name());  // name() is a built-in method that gets the exact name of the enum constant
}

display(Season.WINTER);  // Prints out "WINTER"

U kunt een array van de enum-constanten krijgen met de methode values() . De waarden zijn gegarandeerd in aangiftevolgorde in de geretourneerde array:

Season[] seasons = Season.values();

Opmerking: deze methode wijst een nieuwe reeks waarden toe telkens wanneer deze wordt aangeroepen.


Om de enum-constanten te herhalen:

public static void enumIterate() {
    for (Season s : Season.values()) {
        System.out.println(s.name());
    }
}

U kunt enums gebruiken in een switch :

public static void enumSwitchExample(Season s) {
    switch(s) {
        case WINTER:
            System.out.println("It's pretty cold");
            break;
        case SPRING:
            System.out.println("It's warming up");
            break;
        case SUMMER:
            System.out.println("It's pretty hot");
            break;
        case FALL:
            System.out.println("It's cooling down");
            break;
    }
}

Je kunt ook enum-constanten vergelijken met == :

Season.FALL == Season.WINTER    // false
Season.SPRING == Season.SPRING  // true

Een andere manier om enum-constanten te vergelijken is door equals() zoals hieronder, wat als een slechte gewoonte wordt beschouwd, omdat je als volgt gemakkelijk in valkuilen kunt vallen:

Season.FALL.equals(Season.FALL); // true
Season.FALL.equals(Season.WINTER); // false
Season.FALL.equals("FALL"); // false and no compiler error

Bovendien, hoewel de set instanties in het enum niet kan worden gewijzigd tijdens runtime, zijn de instanties zelf niet inherent onveranderlijk omdat een enum zoals elke andere klasse, veranderlijke velden kan bevatten, zoals hieronder wordt aangetoond.

public enum MutableExample {
    A,
    B;

    private int count = 0;

    public void increment() {
        count++;
    }

    public void print() {
        System.out.println("The count of " + name() + " is " + count);
    }
}

// Usage:
MutableExample.A.print();       // Outputs 0
MutableExample.A.increment();
MutableExample.A.print();       // Outputs 1 -- we've changed a field   
MutableExample.B.print();       // Outputs 0 -- another instance remains unchanged

Het is echter een goede gewoonte om enum instanties onveranderlijk te maken, dat wil zeggen wanneer ze geen extra velden hebben of al dergelijke velden als final zijn gemarkeerd en zelf onveranderlijk zijn. Dit zorgt ervoor dat een enum gedurende de hele levensduur van het programma geen geheugen lekt en dat het veilig is om zijn instanties over alle threads te gebruiken.


Enums implementeert impliciet Serializable en Comparable omdat de Enum klasse doet:

public abstract class Enum<E extends Enum<E>>
extends Object
implements Comparable<E>, Serializable

Enums met constructeurs

Een enum kan geen openbare aannemer hebben; privéconstructors zijn echter acceptabel (constructors voor enums zijn standaard pakket-privaat ):

public enum Coin {
    PENNY(1), NICKEL(5), DIME(10), QUARTER(25); // usual names for US coins
    // note that the above parentheses and the constructor arguments match
    private int value;

    Coin(int value) { 
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

int p = Coin.NICKEL.getValue(); // the int value will be 5

Het wordt aanbevolen om alle velden privé te houden en getter-methoden te bieden, omdat er een eindig aantal instanties voor een opsomming is.


Als je in plaats daarvan een Enum als een class zou implementeren, zou het er als volgt uitzien:

public class Coin<T extends Coin<T>> implements Comparable<T>, Serializable{
    public static final Coin PENNY = new Coin(1);
    public static final Coin NICKEL = new Coin(5);
    public static final Coin DIME = new Coin(10);
    public static final Coin QUARTER = new Coin(25);

    private int value;

    private Coin(int value){
        this.value = value;
    }

    public int getValue() {
        return value;
    }
}

int p = Coin.NICKEL.getValue(); // the int value will be 5

Enum-constanten zijn technisch veranderlijk, dus een setter kan worden toegevoegd om de interne structuur van een enum-constante te wijzigen. Dit wordt echter als een zeer slechte praktijk beschouwd en moet worden vermeden.

De beste praktijk is om Enum-velden onveranderlijk te maken, met final :

public enum Coin {
    PENNY(1), NICKEL(5), DIME(10), QUARTER(25);

    private final int value;

    Coin(int value){ 
        this.value = value;
    }

    ...

}

U kunt meerdere constructors in hetzelfde overzicht definiëren. Als u dat doet, bepalen de argumenten die u in uw opsomming doorgeeft welke constructor wordt genoemd:

public enum Coin {
    PENNY(1, true), NICKEL(5, false), DIME(10), QUARTER(25);

    private final int value;
    private final boolean isCopperColored;

    Coin(int value){
        this(value, false);
    }

    Coin(int value, boolean isCopperColored){ 
        this.value = value;
        this.isCopperColored = isCopperColored;
    }

    ...

}

Opmerking: Alle niet-primitieve enum-velden moeten Serializable implementeren, omdat de Enum klasse dat doet.

Methoden en statische blokken gebruiken

Een opsomming kan een methode bevatten, net als elke klasse. Om te zien hoe dit werkt, verklaren we een opsomming als deze:

public enum Direction {
    NORTH, SOUTH, EAST, WEST;
}

Laten we een methode hebben die het getal in de tegenovergestelde richting retourneert:

public enum Direction {
    NORTH, SOUTH, EAST, WEST;

    public Direction getOpposite(){
        switch (this){
            case NORTH:
                return SOUTH;               
            case SOUTH:
                return NORTH;                
            case WEST:
                return EAST; 
            case EAST:
                return WEST;  
            default: //This will never happen
                return null;
        }
    }
}

Dit kan verder worden verbeterd door het gebruik van velden en statische initialisatieblokken:

public enum Direction {
    NORTH, SOUTH, EAST, WEST;
    
    private Direction opposite;
    
    public Direction getOpposite(){
        return opposite;
    }
    
    static {
        NORTH.opposite = SOUTH;
        SOUTH.opposite = NORTH;
        WEST.opposite = EAST;
        EAST.opposite = WEST;
    }
}

In dit voorbeeld wordt de tegenovergestelde richting opgeslagen in een opposite privéinstantie-veld, dat statisch wordt geïnitialiseerd de eerste keer dat een Direction wordt gebruikt. In dit specifieke geval (omdat NORTH verwijst naar SOUTH en omgekeerd), kunnen we Enums hier niet gebruiken met constructeurs (Constructors NORTH(SOUTH), SOUTH(NORTH), EAST(WEST), WEST(EAST) zouden eleganter zijn en het opposite toestaan aan final worden verklaard, maar zelfreferent zijn en daarom niet zijn toegestaan).

Implementeert interface

Dit is een enum die ook een opvraagbare functie is die String test op vooraf gecompileerde reguliere expressiepatronen.

import java.util.function.Predicate;
import java.util.regex.Pattern;

enum RegEx implements Predicate<String> {
    UPPER("[A-Z]+"), LOWER("[a-z]+"), NUMERIC("[+-]?[0-9]+");

    private final Pattern pattern;

    private RegEx(final String pattern) {
        this.pattern = Pattern.compile(pattern);
    }

    @Override 
    public boolean test(final String input) {
        return this.pattern.matcher(input).matches();
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println(RegEx.UPPER.test("ABC"));
        System.out.println(RegEx.LOWER.test("abc"));
        System.out.println(RegEx.NUMERIC.test("+111"));
    }
}

Elk lid van het overzicht kan ook de methode implementeren:

import java.util.function.Predicate;

enum Acceptor implements Predicate<String> {
    NULL {
        @Override
        public boolean test(String s) { return s == null; }
    },
    EMPTY {
        @Override
        public boolean test(String s) { return s.equals(""); }
    },
    NULL_OR_EMPTY {
        @Override
        public boolean test(String s) { return NULL.test(s) || EMPTY.test(s); }
    };
}

public class Main {
    public static void main(String[] args) {
        System.out.println(Acceptor.NULL.test(null));  // true
        System.out.println(Acceptor.EMPTY.test(""));   // true
        System.out.println(Acceptor.NULL_OR_EMPTY.test(" ")); // false
    }
}

Enum-polymorfismepatroon

Wanneer een methode een "uitbreidbare" reeks enum moet accepteren, kan de programmeur polymorfisme toepassen zoals op een normale class door een interface te maken die overal wordt gebruikt waar de enum s worden gebruikt:

public interface ExtensibleEnum {
    String name();
}

Op deze manier kan elke enum getagd door (de implementatie van) de interface als een parameter worden gebruikt, waardoor de programmeur een variabele hoeveelheid enum kan creëren die door de methode wordt geaccepteerd. Dit kan bijvoorbeeld handig zijn in API's waar er een standaard (niet te wijzigen) enum en de gebruiker van deze API's het enum met meer waarden wil "uitbreiden".

Een set standaard opsommingswaarden kan als volgt worden gedefinieerd:

public enum DefaultValues implements ExtensibleEnum {
    VALUE_ONE, VALUE_TWO;
}

Extra waarden kunnen vervolgens als volgt worden gedefinieerd:

public enum ExtendedValues implements ExtensibleEnum {
    VALUE_THREE, VALUE_FOUR;
}

Voorbeeld dat laat zien hoe de enums te gebruiken - merk op hoe printEnum() waarden van beide enum typen accepteert:

private void printEnum(ExtensibleEnum val) {
    System.out.println(val.name());
}  

printEnum(DefaultValues.VALUE_ONE);    // VALUE_ONE
printEnum(DefaultValues.VALUE_TWO);    // VALUE_TWO
printEnum(ExtendedValues.VALUE_THREE); // VALUE_THREE
printEnum(ExtendedValues.VALUE_FOUR);  // VALUE_FOUR

Opmerking: Dit patroon verhindert niet dat u opsommingswaarden, die al in de ene opsomming zijn gedefinieerd, in een andere opsomming opnieuw kunt definiëren. Deze opsommingswaarden zouden dan verschillende instanties zijn. Het is ook niet mogelijk om switch-on-enum te gebruiken, omdat we alleen de interface hebben, niet de echte enum .

Enums met abstracte methoden

Enums kunnen abstracte methoden definiëren, die elk enum lid moet implementeren.

enum Action {
    DODGE {
        public boolean execute(Player player) {
            return player.isAttacking();
        }
    },
    ATTACK {
        public boolean execute(Player player) {
            return player.hasWeapon();
        }
    },
    JUMP {
        public boolean execute(Player player) {
            return player.getCoordinates().equals(new Coordinates(0, 0));
        }
    };

    public abstract boolean execute(Player player);
}

Hierdoor kan elk opsommingslid zijn eigen gedrag voor een bepaalde bewerking definiëren, zonder typen in een methode in de definitie op het hoogste niveau in te schakelen.

Merk op dat dit patroon een korte vorm is van wat typisch wordt bereikt met behulp van polymorfisme en / of implementatie van interfaces.

Enums documenteren

Niet altijd is de enum naam duidelijk genoeg om te worden begrepen. Gebruik standaard javadoc om een enum te documenteren:

/**
 * United States coins
 */
public enum Coins {
    
    /**
     * One-cent coin, commonly known as a penny, 
     * is a unit of currency equaling one-hundredth 
     * of a United States dollar
     */
    PENNY(1),

    /**
     * A nickel is a five-cent coin equaling 
     * five-hundredth of a United States dollar
     */        
    NICKEL(5),

    /**
     * The dime is a ten-cent coin refers to 
     * one tenth of a United States dollar
     */        
    DIME(10),

    /**
     * The quarter is a US coin worth 25 cents, 
     * one-fourth of a United States dollar
     */        
    QUARTER(25);

    private int value;

    Coins(int value){ 
        this.value = value;
    }

    public int getValue(){
        return value;
    }
}

De waarden van een opsomming verkrijgen

Elke enum-klasse bevat een impliciete statische methode met de naam values() . Deze methode retourneert een array met alle waarden van dat getal. U kunt deze methode gebruiken om de waarden te herhalen. Het is echter belangrijk op te merken dat deze methode elke keer een nieuwe array retourneert.

public enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
    
    /**
    * Print out all the values in this enum.
    */
    public static void printAllDays() {
        for(Day day : Day.values()) {
            System.out.println(day.name());
        }
    }
}

Als u een Set hebt, kunt u ook EnumSet.allOf(Day.class) .

Enum als parameter van het begrensde type

Bij het schrijven van een klasse met generieke geneesmiddelen in Java, is het mogelijk om ervoor te zorgen dat de parameter type een opsomming is. Omdat alle enums de Enum klasse uitbreiden, kan de volgende syntaxis worden gebruikt.

public class Holder<T extends Enum<T>> {
    public final T value;

    public Holder(T init) {
        this.value = init;
    }
}

In dit voorbeeld, het type T moet een opsomming zijn.

Krijg enum constant op naam

Stel dat we een enum DayOfWeek :

enum DayOfWeek {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY;
}

Een opsomming is gecompileerd met een ingebouwde statische waarde van valueOf() methode die kan worden gebruikt om een constante op te zoeken met zijn naam:

String dayName = DayOfWeek.SUNDAY.name();
assert dayName.equals("SUNDAY");

DayOfWeek day = DayOfWeek.valueOf(dayName);
assert day == DayOfWeek.SUNDAY;

Dit is ook mogelijk met een dynamisch opsommingstype:

Class<DayOfWeek> enumType = DayOfWeek.class;
DayOfWeek day = Enum.valueOf(enumType, "SUNDAY");
assert day == DayOfWeek.SUNDAY;

Beide methoden IllegalArgumentException valueOf() IllegalArgumentException een IllegalArgumentException als het opgegeven enum geen constante heeft met een overeenkomende naam.

De Guava-bibliotheek biedt een Enums.getIfPresent() die een Guava Optional retourneert om expliciete uitzonderingsafhandeling te elimineren:

DayOfWeek defaultDay = DayOfWeek.SUNDAY;
DayOfWeek day = Enums.valueOf(DayOfWeek.class, "INVALID").or(defaultDay);
assert day == DayOfWeek.SUNDAY;

Implementeer Singleton-patroon met een opsomming met één element

Enum-constanten worden geïnstantieerd wanneer voor de eerste keer naar een enum wordt verwezen. Daarom is het mogelijk om het Singleton software-ontwerppatroon te implementeren met een enkel element.

public enum Attendant {

    INSTANCE;

    private Attendant() {
        // perform some initialization routine
    }

    public void sayHello() {
        System.out.println("Hello!");
    }
}


public class Main {

    public static void main(String... args) {
        Attendant.INSTANCE.sayHello();// instantiated at this point
    }
}

Volgens het boek "Effective Java" van Joshua Bloch is een opsomming met één element de beste manier om een singleton te implementeren. Deze aanpak heeft de volgende voordelen:

  • draad veiligheid
  • garantie voor enkele instantiatie
  • kant-en-klare serialisatie

En zoals getoond in de sectie implementeert interface, kan deze singleton ook een of meer interfaces implementeren.

Enum met eigenschappen (velden)

In het geval dat we enum met meer informatie willen gebruiken en niet alleen als constante waarden, en we willen twee enums kunnen vergelijken.

Overweeg het volgende voorbeeld:

public enum Coin {
    PENNY(1), NICKEL(5), DIME(10), QUARTER(25);

    private final int value;

    Coin(int value){
        this.value = value;
    }

    public boolean isGreaterThan(Coin other){
        return this.value > other.value;
    }

}

Hier hebben we een Enum genaamd Coin gedefinieerd die de waarde ervan vertegenwoordigt. Met de werkwijze isGreaterThan kunnen we vergelijken met twee enum s:

Coin penny = Coin.PENNY;
Coin dime = Coin.DIME;

System.out.println(penny.isGreaterThan(dime)); // prints: false
System.out.println(dime.isGreaterThan(penny)); // prints: true

Converteer enum naar String

Soms wil je je opsomming omzetten in een string, er zijn twee manieren om dat te doen.

Stel dat we hebben:

public enum Fruit {
    APPLE, ORANGE, STRAWBERRY, BANANA, LEMON, GRAPE_FRUIT;
}

Dus hoe converteren we zoiets als Fruit.APPLE naar "APPLE" ?


Converteren met name()

name() is een interne methode in enum die de String representatie van het enum retourneert, de return String geeft precies aan hoe de enum-waarde is gedefinieerd.

Bijvoorbeeld:

System.out.println(Fruit.BANANA.name());      // "BANANA"
System.out.println(Fruit.GRAPE_FRUIT.name()); // "GRAPE_FRUIT"

Converteer naar toString()

toString() wordt standaard genegeerd om hetzelfde gedrag te hebben als name()

toString() wordt echter waarschijnlijk overschreven door ontwikkelaars om het een gebruiksvriendelijkere String te laten afdrukken

Gebruik toString() als u uw code wilt inchecken, name() is daarvoor veel stabieler. Gebruik alleen toString() als u de waarde wilt uitvoeren naar logs of stdout of zoiets

Standaard:

System.out.println(Fruit.BANANA.toString());      // "BANANA"
System.out.println(Fruit.GRAPE_FRUIT.toString()); // "GRAPE_FRUIT"

Voorbeeld van overschreven worden

System.out.println(Fruit.BANANA.toString());      // "Banana"
System.out.println(Fruit.GRAPE_FRUIT.toString()); // "Grape Fruit"

Enum constant specifiek lichaam

In een enum is het mogelijk om een specifiek gedrag te definiëren voor een bepaalde constante van de enum die het standaardgedrag van de enum , deze techniek staat bekend als constant specifiek lichaam .

Stel dat drie pianostudenten - John, Ben en Luke - als volgt zijn gedefinieerd in een enum naam PianoClass :

    enum PianoClass {
    JOHN, BEN, LUKE;
        public String getSex() {
            return "Male";
        }
        public String getLevel() {
            return "Beginner";
        }
    }

En op een dag arriveren twee andere studenten - Rita en Tom - met een sekse (Vrouw) en niveau (Gemiddeld) die niet overeenkomen met de vorige:

    enum PianoClass2 {
    JOHN, BEN, LUKE, RITA, TOM;
        public String getSex() {
            return "Male"; // issue, Rita is a female
        }
        public String getLevel() {
            return "Beginner"; // issue, Tom is an intermediate student
        }
    }

zodat het eenvoudigweg niet correct is om de nieuwe studenten als volgt aan de constante aangifte toe te voegen:

PianoClass2 tom = PianoClass2.TOM;
PianoClass2 rita = PianoClass2.RITA;
System.out.println(tom.getLevel()); // prints Beginner -> wrong Tom's not a beginner
System.out.println(rita.getSex()); // prints Male -> wrong Rita's not a male

Het is mogelijk om een specifiek gedrag te definiëren voor elk van de constante, Rita en Tom, die het standaardgedrag van PianoClass2 als volgt PianoClass2 :

enum PianoClass3 {
    JOHN, BEN, LUKE,
    RITA {
        @Override
        public String getSex() {
            return "Female";
        }
    },
    TOM {
        @Override
        public String getLevel() {
            return "Intermediate";
        }
    };
    public String getSex() {
        return "Male";
    }
    public String getLevel() {
        return "Beginner";
    }
}

en nu zijn Tom's niveau en Rita's seks zoals ze zouden moeten zijn:

PianoClass3 tom = PianoClass3.TOM;
PianoClass3 rita = PianoClass3.RITA;
System.out.println(tom.getLevel()); // prints Intermediate
System.out.println(rita.getSex()); // prints Female

Een andere manier om een inhoudspecifiek hoofdgedeelte te definiëren, is door constructor te gebruiken, bijvoorbeeld:

enum Friend {
    MAT("Male"),
    JOHN("Male"),
    JANE("Female");
    
    private String gender;

    Friend(String gender) {
        this.gender = gender;
    }

    public String getGender() {
        return this.gender;
    }
}

en gebruik:

Friend mat = Friend.MAT;
Friend john = Friend.JOHN;
Friend jane = Friend.JANE;
System.out.println(mat.getGender());     // Male
System.out.println(john.getGender());    // Male
System.out.println(jane.getGender());    // Female

Geen instantie enum

enum Util {
    /* No instances */;

    public static int clamp(int min, int max, int i) {
        return Math.min(Math.max(i, min), max);
    }

    // other utility methods...
}

Net zoals enum kan worden gebruikt voor singletons (klassen van 1 instantie), kan het worden gebruikt voor gebruiksklassen (klassen van 0 instanties). Zorg er wel voor dat je de (lege) lijst met enum-constanten afsluit met een ; .

Zie de vraag Zero instance enum vs private constructors voor het voorkomen van instantiatie voor een discussie over voor- en nadelen in vergelijking met private constructeurs.

Enums met statische velden

Als uw enum-klasse statische velden moet hebben, houd er dan rekening mee dat ze worden gemaakt na de enum-waarden zelf. Dat betekent dat de volgende code resulteert in een NullPointerException :

enum Example {
    ONE(1), TWO(2);

    static Map<String, Integer> integers = new HashMap<>();

    private Example(int value) {
        integers.put(this.name(), value);
    }
}

Een mogelijke manier om dit op te lossen:

enum Example {
    ONE(1), TWO(2);

    static Map<String, Integer> integers;

    private Example(int value) {
        putValue(this.name(), value);
    }

    private static void putValue(String name, int value) {
        if (integers == null)
            integers = new HashMap<>();
        integers.put(name, value);
    }
}

Initialiseer het statische veld niet:

enum Example {
    ONE(1), TWO(2);

    // after initialisisation integers is null!!
    static Map<String, Integer> integers = null;

    private Example(int value) {
        putValue(this.name(), value);
    }

    private static void putValue(String name, int value) {
        if (integers == null)
            integers = new HashMap<>();
        integers.put(name, value);
    }
    // !!this may lead to null poiner exception!!
    public int getValue(){
        return (Example.integers.get(this.name()));
    }
}

initialisisation:

  • maak de opsommingswaarden
    • als bijwerking putValue () genoemd die gehele getallen initialiseert
  • de statische waarden zijn ingesteld
    • gehele getallen = null; // wordt uitgevoerd na de enums, zodat de inhoud van gehele getallen verloren gaat

Vergelijk en bevat voor Enum-waarden

Enums bevat alleen constanten en kan direct worden vergeleken met == . Er is dus alleen referentiecontrole nodig, u hoeft de methode .equals niet te gebruiken. Bovendien, als .equals verkeerd gebruikt, kan de NullPointerException terwijl dat niet het geval is met == check.

enum Day {
    GOOD, AVERAGE, WORST;
}

public class Test {

    public static void main(String[] args) {
        Day day = null;

        if (day.equals(Day.GOOD)) {//NullPointerException!
            System.out.println("Good Day!");
        }

        if (day == Day.GOOD) {//Always use == to compare enum
            System.out.println("Good Day!");
        }

    }
}

Om de enum-waarden te groeperen, aan te vullen, te variëren, hebben we de EnumSet klasse die verschillende methoden bevat.

  • EnumSet#range : om een subset van enum te krijgen op bereik gedefinieerd door twee eindpunten

  • EnumSet#of : Set van specifieke enums zonder bereik. Meerdere overladen of methoden zijn er.

  • EnumSet#complementOf : set van enum die een aanvulling is op enum-waarden in de parameter parameter

    enum Page {
       A1, A2, A3, A4, A5, A6, A7, A8, A9, A10
    }
    
    public class Test {
    
      public static void main(String[] args) {
          EnumSet<Page> range = EnumSet.range(Page.A1, Page.A5);
    
          if (range.contains(Page.A4)) {
              System.out.println("Range contains A4");
          }
    
          EnumSet<Page> of = EnumSet.of(Page.A1, Page.A5, Page.A3);
    
          if (of.contains(Page.A1)) {
              System.out.println("Of contains A1");
          }
      }
    }
    


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow