enum în Java

enum declară un tip cu un set fix de valori cu nume (zilele săptămânii, stările unei comenzi), verificat de compilator.

Sintaxă
enum Anotimp { PRIMAVARA, VARA, TOAMNA, IARNA }

Anotimp a = Anotimp.VARA;
a.name();       // "VARA"
a.ordinal();    // 1
Anotimp.values();
Anotimp.valueOf("IARNA");

Ce face enum

Un enum este o clasă specială care are exact valorile enumerate în declarație și nimic altceva. În locul unor constante int sau String (unde oricine poate scrie "TOMANA" greșit), folosești Anotimp.TOAMNA, iar compilatorul verifică orice valoare.

Fiecare enum primește automat metodele values() (toate valorile, în ordinea declarării), valueOf("NUME") (din text în constantă), name() (numele exact) și ordinal() (poziția, de la 0). Constantele se compară sigur cu ==, pentru că fiecare există o singură dată.

Enum-urile merg foarte bine în switch: în case scrii doar numele constantei, iar un switch expresie care acoperă toate constantele nu are nevoie de default. Pentru dicționare și mulțimi cu chei enum există EnumMap și EnumSet, foarte rapide. Enum-urile pot avea și câmpuri și metode (vezi enum cu metode).

Exemple

Exemplul 1: Declarare, values(), name() și ordinal()

values() parcurge constantele în ordinea declarării. valueOf transformă textul în constantă; pentru un text necunoscut aruncă IllegalArgumentException.

enum Anotimp { PRIMAVARA, VARA, TOAMNA, IARNA }

public class Main {
    public static void main(String[] args) {
        for (Anotimp a : Anotimp.values()) {
            System.out.println(a.ordinal() + ": " + a.name());
        }

        Anotimp ales = Anotimp.valueOf("TOAMNA");
        System.out.println("ales: " + ales + ", e toamnă? " + (ales == Anotimp.TOAMNA));

        try {
            Anotimp.valueOf("Toamna");
        } catch (IllegalArgumentException e) {
            System.out.println("eroare: " + e.getMessage());
        }
    }
}

Rezultat

0: PRIMAVARA
1: VARA
2: TOAMNA
3: IARNA
ales: TOAMNA, e toamnă? true
eroare: No enum constant Anotimp.Toamna

Exemplul 2: enum în switch

Expresia switch acoperă toate cele patru stări, deci nu are nevoie de default. Dacă adaugi o stare nouă în enum, compilatorul semnalează switch-ul incomplet.

enum StareComanda { PLASATA, EXPEDIATA, LIVRATA, ANULATA }

public class Main {
    static String mesaj(StareComanda s) {
        return switch (s) {
            case PLASATA -> "Comanda a fost înregistrată.";
            case EXPEDIATA -> "Coletul este la curier.";
            case LIVRATA -> "Coletul a ajuns. Poftă bună!";
            case ANULATA -> "Comanda a fost anulată.";
        };
    }

    public static void main(String[] args) {
        StareComanda[] istoric = {StareComanda.PLASATA, StareComanda.EXPEDIATA, StareComanda.LIVRATA};
        for (StareComanda s : istoric) {
            System.out.println(s + ": " + mesaj(s));
        }
    }
}

Rezultat

PLASATA: Comanda a fost înregistrată.
EXPEDIATA: Coletul este la curier.
LIVRATA: Coletul a ajuns. Poftă bună!

Exemplul 3: EnumMap pentru numărare

EnumMap păstrează cheile în ordinea declarării din enum, deci afișarea este mereu aceeași.

import java.util.EnumMap;
import java.util.Map;

enum Zi { LUNI, MARTI, MIERCURI, JOI, VINERI, SAMBATA, DUMINICA }

public class Main {
    public static void main(String[] args) {
        Zi[] comenzi = {Zi.VINERI, Zi.LUNI, Zi.VINERI, Zi.SAMBATA, Zi.LUNI, Zi.VINERI};
        Map<Zi, Integer> pe = new EnumMap<>(Zi.class);
        for (Zi z : comenzi) {
            pe.merge(z, 1, Integer::sum);
        }
        System.out.println(pe);
        System.out.println("SAMBATA vine după VINERI? " + (Zi.SAMBATA.compareTo(Zi.VINERI) > 0));
    }
}

Rezultat

{LUNI=2, VINERI=3, SAMBATA=1}
SAMBATA vine după VINERI? true

Greșeli frecvente

  • Scrii case Anotimp.VARA: în switch-uri vechi; până la Java 21 era eroare. Scrie doar case VARA.
  • Salvezi în baza de date ordinal(). Dacă reordonezi sau adaugi constante, numerele se schimbă. Salvează name().
  • Folosești valueOf pe text venit de la utilizator fără să tratezi IllegalArgumentException: valueOf face diferența între litere mari și mici.

Comenzi înrudite

  • enum cu câmpuri și metode: Un enum poate avea câmpuri, constructor, metode, metode diferite pentru fiecare constantă și poate implementa interfețe.
  • switch, case și default: Alege ce cod se execută comparând o valoare cu mai multe constante case; default tratează orice altă valoare.
  • switch expressions și yield: switch folosit ca expresie care produce o valoare; yield returnează valoarea dintr-o ramură cu bloc.
  • sealed, permits și non-sealed: O clasă sau interfață sealed își alege explicit subtipurile (permits); fiecare subtip este final, sealed sau non-sealed.