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 doarcase VARA. - Salvezi în baza de date
ordinal(). Dacă reordonezi sau adaugi constante, numerele se schimbă. Salveazăname(). - Folosești
valueOfpe text venit de la utilizator fără să trateziIllegalArgumentException:valueOfface 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.