W3docs

Java Enums

Definisci un insieme fisso di costanti in Java con i tipi enum, inclusi enum con campi, costruttori e metodi.

Un enum è una classe le cui istanze costituiscono un insieme fisso, noto al momento della compilazione. I giorni della settimana, i colori del semaforo, gli stati di un ordine — tutto ciò in cui i valori ammissibili sono un elenco piccolo e nominato. Una volta scritto enum Status { OPEN, CLOSED }, quei due sono gli unici valori Status che esisteranno mai, e il compilatore ti avviserà se provi a inventarne un terzo.

Gli enum sostituiscono la vecchia abitudine del C di usare public static final int OPEN = 0;. Le costanti intere non offrono sicurezza sui tipi — setStatus(7) compila senza errori — ma setStatus(Status status) accetta solo uno dei valori dichiarati.

Dichiarare un enum

La forma più semplice è semplicemente un elenco di nomi di costanti:

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

Usalo come qualsiasi altro tipo:

Direction d = Direction.NORTH;
if (d == Direction.NORTH) System.out.println("heading up");

Ogni costante è un'istanza singleton di Direction. Confrontare con == è corretto e idiomatico — esiste un solo NORTH nella JVM, quindi l'uguaglianza di riferimento coincide con l'uguaglianza di valore.

In uno switch

Gli enum e le istruzioni switch sono fatti l'uno per l'altro:

switch (d) {
  case NORTH -> System.out.println("up");
  case SOUTH -> System.out.println("down");
  case EAST, WEST -> System.out.println("sideways");
}

Nota il semplice NORTH al posto di Direction.NORTH — all'interno di un switch su un enum, il compilatore conosce il tipo. Se aggiungi una nuova costante e dimentichi di gestirla in un'espressione switch, riceverai un errore di compilazione per mancanza di esaustività: esattamente la rete di sicurezza che desideri.

Campi, costruttori e metodi

Un enum può contenere dati e comportamento. Ogni costante viene costruita con argomenti e il corpo dell'enum può definire metodi normali:

public enum Planet {
  MERCURY(3.303e+23, 2.4397e6),
  EARTH  (5.976e+24, 6.37814e6),
  MARS   (6.421e+23, 3.3972e6);

  private final double massKg;
  private final double radiusM;

  Planet(double massKg, double radiusM) {
    this.massKg  = massKg;
    this.radiusM = radiusM;
  }

  public double surfaceGravity() {
    final double G = 6.67300E-11;
    return G * massKg / (radiusM * radiusM);
  }
}

Due regole da ricordare:

  • L'elenco delle costanti viene prima nel corpo, separato dal resto da un punto e virgola.
  • Il costruttore è implicitamente privato — gli enum non possono essere istanziati dall'esterno, il che è proprio il loro scopo.

Metodi incorporati

Ogni enum riceve gratuitamente alcuni metodi:

  • name() restituisce il nome dichiarato della costante come String.
  • ordinal() restituisce la sua posizione nella dichiarazione (a base zero). Utile occasionalmente; evita di persisterne il valore perché riordinare le costanti ne cambia silenziosamente il significato.
  • values() restituisce un array di tutte le costanti nell'ordine di dichiarazione — ottimo per i cicli for (Direction d : Direction.values()). Costruisce un nuovo array ad ogni chiamata, quindi memorizzalo in una variabile locale se iteri in un ciclo critico per le prestazioni.
  • valueOf(String) cerca una costante per nome esatto (sensibile alle maiuscole) e lancia IllegalArgumentException se non trova corrispondenza.

Poiché valueOf lancia un'eccezione su input sconosciuto, proteggila quando la stringa proviene dall'esterno del codice — input utente, file, payload di rete:

Direction d = Direction.valueOf("EAST");   // EAST
try {
  Direction.valueOf("UP");                 // not a declared constant
} catch (IllegalArgumentException e) {
  System.out.println("no such constant");  // no such constant
}

Comportamento per costante

A volte una costante deve comportarsi diversamente dalle altre. Puoi sovrascrivere metodi per costante con un corpo anonimo:

public enum Operation {
  PLUS  { public int apply(int a, int b) { return a + b; } },
  MINUS { public int apply(int a, int b) { return a - b; } },
  TIMES { public int apply(int a, int b) { return a * b; } };

  public abstract int apply(int a, int b);
}

Ogni costante diventa una piccola sottoclasse anonima di Operation che implementa apply. Il pattern strategy è incluso gratuitamente.

Implementare interfacce

Gli enum possono implementare interfacce — semplicemente non possono estendere altre classi (estendono implicitamente java.lang.Enum):

public enum Day implements Runnable {
  MONDAY, TUESDAY;
  public void run() { System.out.println("today is " + name()); }
}

Questo è un modo elegante per collegare una famiglia fissa di strategie a codice che accetta qualsiasi Runnable.

EnumSet e EnumMap

Quando hai bisogno di un Set o di una Map con chiave enum, preferisci EnumSet e EnumMap rispetto a HashSet/HashMap. Entrambi sono supportati da un vettore di bit o da un array semplice dimensionato sull'enum, quindi evitano completamente l'hashing — le ricerche sono un singolo indice di array, e un EnumSet di un piccolo enum entra in un solo long:

EnumSet<Direction> horizontal = EnumSet.of(Direction.EAST, Direction.WEST);
EnumSet<Direction> all        = EnumSet.allOf(Direction.class);   // every constant
EnumSet<Direction> none       = EnumSet.noneOf(Direction.class);  // empty, ready to fill

EnumMap<Direction, String> labels = new EnumMap<>(Direction.class);
labels.put(Direction.NORTH, "up");

L'iterazione su un EnumSet o EnumMap segue l'ordine di dichiarazione, rendendo l'output deterministico — un altro motivo per preferirli alle collezioni basate su hash.

Un esempio pratico

java— editable, runs on the server

Prossimi passi

Gli enum bloccano un insieme fisso di istanze. Il prossimo capitolo introduce una forma diversa di classe ristretta — i record, progettati per essere semplici contenitori di dati immutabili. Continua su Java records.

Pratica

Pratica
Qual è il motivo principale per usare un enum invece di un insieme di costanti int?
Qual è il motivo principale per usare un enum invece di un insieme di costanti int?
Was this page helpful?