Ricerca…


introduzione

Le enumerazioni Java (dichiarate usando la parola chiave enum ) sono sintassi abbreviata per quantità considerevoli di costanti di una singola classe.

Sintassi

  • [public / protected / private] enum Enum_name {// Dichiara un nuovo enum.
  • ENUM_CONSTANT_1 [, ENUM_CONSTANT_2 ...]; // Dichiara le costanti enum. Questa deve essere la prima riga all'interno dell'enumerazione e deve essere separata da virgole, con un punto e virgola alla fine.
  • ENUM_CONSTANT_1 (param) [, ENUM_CONSTANT_2 (param) ...]; // Dichiara le costanti enum con i parametri. I tipi di parametri devono corrispondere al costruttore.
  • ENUM_CONSTANT_1 {...} [, ENUM_CONSTANT_2 {...} ...]; // Dichiara le costanti enum con metodi sottoposti a override. Questo deve essere fatto se l'enum contiene metodi astratti; tutti questi metodi devono essere implementati.
  • ENUM_CONSTANT.name () // Restituisce una stringa con il nome della costante enum.
  • ENUM_CONSTANT.ordinal () // Restituisce l'ordinale di questa costante di enumerazione, la sua posizione nella sua dichiarazione enum, dove alla costante iniziale è assegnato un ordinale pari a zero.
  • Enum_name.values ​​() // Restituisce una nuova matrice (di tipo Enum_name []) contenente ogni costante di quell'enumerazione ogni volta che viene chiamata.
  • Enum_name.valueOf ("ENUM_CONSTANT") // L'inverso di ENUM_CONSTANT.name () - restituisce la costante enum con il nome specificato.
  • Enum.valueOf (Enum_name.class, "ENUM_CONSTANT") // Un sinonimo del precedente: L'inverso di ENUM_CONSTANT.name () - restituisce la costante enum con il nome specificato.

Osservazioni

restrizioni

Enum estende sempre java.lang.Enum , quindi è impossibile per un enum estendere una classe. Tuttavia, possono implementare molte interfacce.

Consigli e trucchi

A causa della loro rappresentazione specializzata, ci sono mappe e insiemi più efficienti che possono essere usati con le enumerhe come chiavi. Questi saranno spesso più veloci delle loro controparti non specializzate.

Dichiarare e usare un enum di base

Enum può essere considerato come lo zucchero di sintassi per una classe sigillata che viene istanziata solo un numero di volte noto in fase di compilazione per definire un insieme di costanti.

Un enum semplice per elencare le diverse stagioni sarebbe dichiarato come segue:

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

Anche se le costanti enum non devono necessariamente essere in maiuscolo, è convenzione Java che i nomi delle costanti sono interamente in maiuscolo, con le parole separate da caratteri di sottolineatura.


Puoi dichiarare un Enum nel suo file:

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

Ma puoi anche dichiararlo in un'altra classe:

 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
    }

}

Infine, non puoi dichiarare un Enum all'interno di un corpo o costruttore di un metodo:

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

Le costanti enum duplicate non sono consentite:

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

Ogni costante di enum è public , static e final di default. Poiché ogni costante è static , è possibile accedervi direttamente utilizzando il nome dell'enumerazione.

Le costanti Enum possono essere passate come parametri del metodo:

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"

È possibile ottenere un array di costanti enum utilizzando il metodo values() . I valori sono garantiti per essere nell'ordine di dichiarazione nell'array restituito:

Season[] seasons = Season.values();

Nota: questo metodo alloca un nuovo array di valori ogni volta che viene chiamato.


Per scorrere le costanti enum:

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

È possibile utilizzare le enumerazioni in un'istruzione 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;
    }
}

Puoi anche confrontare le costanti enum usando == :

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

Un altro modo per confrontare le costanti enum è usando equals() come sotto, che è considerato una cattiva pratica in quanto si può facilmente cadere in insidie ​​come segue:

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

Inoltre, sebbene l'insieme di istanze enum non possa essere modificato in fase di esecuzione, le istanze stesse non sono intrinsecamente immutabili poiché come qualsiasi altra classe, un enum può contenere campi mutabili come illustrato di seguito.

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

Tuttavia, una buona pratica è rendere le istanze enum immutabili, cioè quando non hanno campi aggiuntivi o tutti questi campi sono contrassegnati come final e sono immutabili. Ciò garantirà che per tutta la durata dell'applicazione l' enum non perderà memoria e che è sicuro utilizzare le sue istanze su tutti i thread.


Enum implementa implicitamente Serializable e Comparable perché la classe Enum esegue:

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

Enum con costruttori

Un enum non può avere un costruttore pubblico; tuttavia, i costruttori privati ​​sono accettabili (i costruttori per le enumerazioni sono pacchetti-privati per impostazione predefinita):

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

Si consiglia di mantenere tutti i campi privati ​​e di fornire metodi getter, in quanto vi è un numero finito di istanze per un enum.


Se invece dovessi implementare un Enum come class , assomiglierebbe a questo:

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

Le costanti Enum sono tecnicamente mutabili, quindi è possibile aggiungere un setter per modificare la struttura interna di una costante enum. Tuttavia, questa è considerata una pratica molto negativa e dovrebbe essere evitata.

La migliore pratica è rendere immutabili i campi Enum, con final :

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

    private final int value;

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

    ...

}

È possibile definire più costruttori nella stessa enumerazione. Quando lo fai, gli argomenti che passi nella tua dichiarazione enum decidono quale costruttore è chiamato:

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

    ...

}

Nota: tutti i campi enumerati non primitivi dovrebbero implementare Serializable perché la classe Enum fa.

Utilizzo di metodi e blocchi statici

Un enum può contenere un metodo, proprio come qualsiasi classe. Per vedere come funziona, dichiareremo un enume come questo:

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

Prendiamo un metodo che restituisce l'enum nella direzione opposta:

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

Questo può essere ulteriormente migliorato attraverso l'uso di campi e blocchi di inizializzazione statici:

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 questo esempio, la direzione opposta viene memorizzata in un campo di istanza privato opposite , che viene inizializzato staticamente la prima volta che viene utilizzata una Direction . In questo caso particolare (perché NORTH riferimento al SOUTH e viceversa), non possiamo usare Enum con costruttori qui (Costruttori NORTH(SOUTH), SOUTH(NORTH), EAST(WEST), WEST(EAST) sarebbe più elegante e consentirebbe il opposite essere dichiarato final , ma sarebbe autoreferenziale e quindi non consentito).

Interfaccia di implementazioni

Questa è una enum che è anche una funzione callable che verifica gli input di String contro i modelli di espressioni regolari precompilati.

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

Ogni membro dell'enum può anche implementare il metodo:

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 Polymorphism Pattern

Quando un metodo deve accettare un insieme "enensibile" di valori enum , il programmatore può applicare il polimorfismo come in una class normale creando un'interfaccia che sarà utilizzata in qualsiasi altro punto in cui l' enum deve essere usato:

public interface ExtensibleEnum {
    String name();
}

In questo modo, qualsiasi enum taggato da (implementando) l'interfaccia può essere usato come parametro, consentendo al programmatore di creare una quantità variabile di enum che sarà accettata dal metodo. Questo può essere utile, ad esempio, nelle API in cui esiste un enum predefinito (non modificabile) e l'utente di queste API desidera "estendere" l' enum con più valori.

Una serie di valori di enum predefiniti può essere definita come segue:

public enum DefaultValues implements ExtensibleEnum {
    VALUE_ONE, VALUE_TWO;
}

Valori aggiuntivi possono quindi essere definiti in questo modo:

public enum ExtendedValues implements ExtensibleEnum {
    VALUE_THREE, VALUE_FOUR;
}

Esempio che mostra come usare le enumerazioni - si noti come printEnum() accetta valori da entrambi i enum tipi:

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

Nota: questo modello non impedisce di ridefinire i valori enum, che sono già definiti in un enum, in un altro enum. Questi valori di enumerazione sarebbero quindi diversi istanze. Inoltre, non è possibile utilizzare switch-on-enum poiché tutto ciò che abbiamo è l'interfaccia, non il vero enum .

Enums con metodi astratti

Enums può definire metodi astratti, che ogni membro enum è tenuto a implementare.

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

Ciò consente a ciascun membro di enum di definire il proprio comportamento per una determinata operazione, senza dover attivare i tipi in un metodo nella definizione di livello superiore.

Si noti che questo modello è una forma breve di ciò che viene tipicamente ottenuto usando il polimorfismo e / o l'implementazione di interfacce.

Documentare le enumerazioni

Non sempre il nome enum è abbastanza chiaro per essere compreso. Per documentare un enum , usa javadoc standard:

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

Ottenere i valori di un enum

Ogni classe enum contiene un metodo statico implicito denominato values() . Questo metodo restituisce una matrice contenente tutti i valori di quell'enumerazione. È possibile utilizzare questo metodo per scorrere i valori. È importante notare tuttavia che questo metodo restituisce un nuovo array ogni volta che viene chiamato.

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

Se hai bisogno di un Set puoi anche usare EnumSet.allOf(Day.class) .

Enum come parametro di tipo limitato

Quando si scrive una classe con generics in java, è possibile assicurarsi che il parametro type sia un enum. Poiché tutte le enumerazioni estendono la classe Enum , è possibile utilizzare la seguente sintassi.

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

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

In questo esempio, il tipo T deve essere un enum.

Ottieni costante enum per nome

Diciamo che abbiamo un enum DayOfWeek :

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

Un enum è compilato con un metodo built-in statico valueOf() che può essere usato per cercare una costante con il suo nome:

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

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

Questo è anche possibile usando un tipo enum dinamico:

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

Entrambi questi metodi valueOf() generano un IllegalArgumentException se l'enum specificato non ha una costante con un nome corrispondente.

La libreria Guava fornisce un metodo di supporto Enums.getIfPresent() che restituisce un Optional Guava per eliminare la gestione delle eccezioni esplicite:

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

Implementa il pattern Singleton con un enum a elemento singolo

Le costanti Enum vengono istanziate quando un enum viene referenziato per la prima volta. Pertanto, ciò consente di implementare il modello di progettazione software Singleton con un enum a elemento singolo.

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

Secondo il libro "Effective Java" di Joshua Bloch, un enum a elemento singolo è il modo migliore per implementare un singleton. Questo approccio ha i seguenti vantaggi:

  • sicurezza del filo
  • garanzia di singola istanziazione
  • serializzazione pronta all'uso

E come mostrato nella sezione implements interface questo singleton potrebbe anche implementare una o più interfacce.

Enum con proprietà (campi)

Nel caso in cui vogliamo usare enum con più informazioni e non solo come valori costanti, e vogliamo essere in grado di confrontare due enumerazioni.

Considera il seguente esempio:

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

}

Qui abbiamo definito un Enum chiamato Coin che rappresenta il suo valore. Con il metodo isGreaterThan possiamo confrontare due enum :

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

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

Converti enum in stringa

A volte vuoi convertire il tuo enum in una stringa, ci sono due modi per farlo.

Supponiamo di avere:

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

Quindi, come possiamo convertire qualcosa come Fruit.APPLE in "APPLE" ?


Converti usando il name()

name() è un metodo interno in enum che restituisce la rappresentazione String dell'enumerazione, la String ritorno rappresenta esattamente il modo in cui è stato definito il valore enum.

Per esempio:

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

Converti usando toString()

toString() è, per impostazione predefinita , sottoposto a override per avere lo stesso comportamento di name()

Tuttavia, toString() è probabilmente sovrascritto dagli sviluppatori per farlo stampare una String più user-friendly

Non usare toString() se vuoi fare il check-in del tuo codice, name() è molto più stabile per quello. Utilizzare toString() quando si intende emettere il valore su logs o stdout o qualcosa del genere

Di default:

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

Esempio di sovrascrittura

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

Enum corpo specifico costante

In un enum è possibile definire un comportamento specifico per una particolare costante enum che sovrascrive il comportamento predefinito enum , questa tecnica è nota come corpo specifico costante .

Supponiamo che tre studenti di pianoforte - John, Ben e Luke - siano definiti in un enum chiamato PianoClass , come segue:

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

E un giorno arrivano altri due studenti - Rita e Tom - con un sesso (femmina) e un livello (intermedio) che non corrispondono ai precedenti:

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

cosicché aggiungere semplicemente i nuovi studenti alla dichiarazione costante, come segue, non è corretto:

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

È possibile definire un comportamento specifico per ciascuna costante, Rita e Tom, che sovrascrivono il comportamento predefinito PianoClass2 come segue:

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

e ora il livello di Tom e il sesso di Rita sono come dovrebbero essere:

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

Un altro modo per definire il corpo specifico del contenuto è utilizzando il costruttore, ad esempio:

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

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

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

e utilizzo:

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

Zero istanza 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...
}

Proprio come enum può essere usato per singleton (1 classi di istanze), può essere usato per classi di utilità (0 classi di istanze). Assicurati di terminare la lista (vuota) di costanti enum con a ; .

Vedi la domanda Zero istanza enum vs costruttori privati ​​per prevenire l'istanziazione per una discussione su pro e contro rispetto ai costruttori privati.

Enum con campi statici

Se è richiesta la classe enum per avere campi statici, tenere presente che vengono creati dopo i valori enum stessi. Ciò significa che il codice seguente genererà una NullPointerException :

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

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

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

Un modo possibile per risolvere questo problema:

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

Non inizializzare il campo statico:

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:

  • crea i valori enum
    • come effetto collaterale putValue () chiamato che inizializza interi
  • i valori statici sono impostati
    • interi = null; // viene eseguito dopo l'enumerazione, quindi il contenuto degli interi viene perso

Confronta e contiene per i valori Enum

Enum contiene solo costanti e può essere confrontato direttamente con == . Quindi, è necessario solo un controllo di riferimento, non è necessario utilizzare il metodo .equals . Inoltre, se .equals utilizzato in modo errato, può aumentare NullPointerException mentre non è il caso con il controllo == .

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

    }
}

Per raggruppare, completare, estendere i valori enum abbiamo classe EnumSet che contiene metodi diversi.

  • EnumSet#range : per ottenere sottoinsieme di enum per intervallo definito da due endpoint

  • EnumSet#of : insieme di enumerazioni specifiche senza intervallo. Esistono più overload of metodi.

  • EnumSet#complementOf : set di enum che è complementare ai valori enum forniti nel parametro method

    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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow