1. Wprowadzenie
W programowaniu często trzeba operować listami z góry znanych, ograniczonych wariantów. Na przykład: dni tygodnia, kolory sygnalizacji świetlnej, poziomy trudności gry, statusy zamówienia. Każdy z tych wariantów jest zwykle reprezentowany stałą wartością. I tu zbliżamy się do dzisiejszego tematu – wyliczeń (enum).
Wyliczenie to specjalny typ danych, który pozwala deklarować zbiór nazwanych stałych.
enum – jak pudełko z przegródkami i etykietami, gdzie każda etykieta to unikalna nazwa powiązana z liczbą.
Najważniejsze zalety enum:
- Twój kod staje się czytelny i samodokumentujący;
- Zamiast tajemniczych „magicznych liczb” w rodzaju 0, 1, 2 pojawiają się wyraziste nazwy: DayOfWeek.MONDAY lub TrafficLight.RED;
- Kompilator zgłosi błąd, jeśli spróbujesz przypisać nieprawidłową wartość;
- Pod każdym elementem kryje się… zwykła liczba całkowita! (Do tego jeszcze wrócimy.)
Składnia deklaracji enum
// Ogólny szablon deklaracji wyliczenia
public enum Name
{
KONSTANTA1 ,
KONSTANTA2 ,
KONSTANTA3
}
Zadeklarować wyliczenie w Javie jest bardzo prosto. Oto podstawowy przykład:
// Plik DayOfWeek.java
public enum DayOfWeek {
MONDAY, // 0
TUESDAY, // 1
WEDNESDAY, // 2
THURSDAY, // 3
FRIDAY, // 4
SATURDAY, // 5
SUNDAY // 6
}
Wyjaśnienie:
- Słowo kluczowe enum mówi kompilatorowi: „To jest wyliczenie!”
- W klamrach, oddzielone przecinkami, znajdują się nazwy wariantów (stałych).
- Przyjęło się pisać nazwy w UPPER_SNAKE_CASE (wszystkie litery wielkie, słowa oddzielone podkreśleniem).
Gdzie można zadeklarować enum?
- W osobnym pliku (DayOfWeek.java).
- Wewnątrz klasy (jeśli potrzebne jest prywatne wyliczenie tylko dla tej klasy).
- Nawet wewnątrz metody (choć robi się tak rzadko).
2. Użycie enum w kodzie
Deklaracja zmiennej typu enum:
DayOfWeek today = DayOfWeek.MONDAY;
Teraz today może przyjmować tylko jedną z wartości zadeklarowanych w DayOfWeek.
Przykład użycia w switch
switch (today)
{
case MONDAY:
System.out.println("Och, poniedziałek...");
break;
case FRIDAY:
System.out.println("Hurra, piątek!");
break;
default:
System.out.println("Zwykły dzień.");
}
Ważna różnica: w case piszemy samo imię stałej (bez prefiksu), jeśli typ zmiennej jest już znany kompilatorowi.
Iteracja po wszystkich wartościach enum
Każdy enum ma statyczną metodę values(), która zwraca tablicę wszystkich jego wartości:
for (DayOfWeek day : DayOfWeek.values())
{
System.out.println(day);
}
To bardzo wygodne do wyświetlania menu, walidacji, generowania wariantów itd.
3. Metody enum: name(), ordinal(), valueOf()
Wyliczenia w Javie to nie tylko listy stałych, lecz pełnoprawne klasy z metodami!
Metoda name()
Zwraca nazwę stałej jako napis (dokładnie tak, jak jest zapisana w kodzie):
DayOfWeek day = DayOfWeek.FRIDAY;
System.out.println(day.name()); // "FRIDAY"
Metoda ordinal()
Zwraca indeks porządkowy stałej (liczony od zera):
System.out.println(DayOfWeek.MONDAY.ordinal()); // 0
System.out.println(DayOfWeek.FRIDAY.ordinal()); // 4
Uwaga: Nie należy przechowywać ani porównywać enumów po ordinal(), jeśli kolejność może się w przyszłości zmienić! Lepiej używać nazw.
Metoda valueOf(String name)
Konwertuje napis na wartość enum, jeśli taka stała istnieje:
DayOfWeek day = DayOfWeek.valueOf("MONDAY");
System.out.println(day); // MONDAY
Jeśli napisy się nie zgadzają — zostanie rzucony wyjątek IllegalArgumentException.
Metoda values()
Zwraca tablicę wszystkich wartości enum (przykład był wyżej):
DayOfWeek[] days = DayOfWeek.values();
4. Enum z polami, konstruktorem i metodami
Wyliczenia w Javie można rozszerzać: dodawać pola, konstruktory, metody! Tak, to nie tylko lista nazw, lecz mini-klasa.
Przykład: dni tygodnia ze zlokalizowaną nazwą
public enum DayOfWeek
{
MONDAY("Poniedziałek"),
TUESDAY("Wtorek"),
WEDNESDAY("Środa"),
THURSDAY("Czwartek"),
FRIDAY("Piątek"),
SATURDAY("Sobota"),
SUNDAY("Niedziela");
private final String russianName;
// Konstruktor (domyślnie private)
DayOfWeek(String russianName)
{
this.russianName = russianName;
}
public String getRussianName()
{
return russianName;
}
}
Więcej o tym, jak to działa, dowiesz się, gdy zaczniemy omawiać OOP na poziomach 27+ :P
Teraz można zrobić tak:
DayOfWeek day = DayOfWeek.WEDNESDAY;
System.out.println(day.getRussianName()); // "Środa"
Fiszka: Każda wartość enum może mieć własne dane (w tym przypadku – polska nazwa).
Zalety używania enum
- Bezpieczeństwo typów: nie można przypadkowo przypisać zmiennej enum wartości, której nie ma na liście.
- Czytelność: kod sam się dokumentuje (TrafficLight.RED zamiast 1 lub "red").
- Wygoda utrzymania: gdy trzeba dodać lub usunąć wariant, robisz to w jednym miejscu.
- Działa ze switch: enum idealnie pasuje do rozgałęzień po wartościach.
- Możliwość rozszerzania: dodawanie pól, metod, implementacja interfejsów.
- Mniej błędów: kompilator pomoże nie zapomnieć obsłużyć wariantów (zwłaszcza w konstrukcjach switch).
6. Praktyka: używamy enum w naszej aplikacji
Dodajmy do naszej miniaplikacji obsługę dni tygodnia poprzez enum.
Krok 1. Zadeklarujmy enum
public enum DayOfWeek
{
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
Krok 2. Użycie w kodzie
System.out.println("Wprowadź dzień tygodnia (np. MONDAY):");
Scanner console = new Scanner(System.in);
String input = console.nextLine().toUpperCase();
DayOfWeek day = DayOfWeek.valueOf(input);
switch (day)
{
case MONDAY:
System.out.println("Początek tygodnia pracy!");
break;
case FRIDAY:
System.out.println("Wkrótce weekend!");
break;
case SATURDAY:
case SUNDAY:
System.out.println("Hura, weekend!");
break;
default:
System.out.println("Zwykły dzień roboczy.");
}
Co się dzieje:
- Użytkownik wpisuje dzień tygodnia (na przykład "monday" lub "MONDAY").
- Zamieniamy napis na wielkie litery (toUpperCase()), aby uniezależnić się od wielkości liter.
- Konwertujemy napis na wartość enum za pomocą valueOf.
- Używamy switch, aby wyświetlić różne komunikaty.
- Jeśli wpisano coś niepoprawnego — łapiemy błąd i wyświetlamy ostrzeżenie.
7. Typowe błędy podczas pracy z enum
Błąd nr 1: używanie napisów lub liczb zamiast enum. Bardzo często początkujący programiści nadal piszą tak:
int day = 1; // 1 – to poniedziałek?
albo
String status = "DELIVERED";
To złe podejście: łatwo o literówki, trudne do utrzymania. Używaj enum!
Błąd nr 2: porównywanie enum przez == i .equals(). W Javie wartości enum można porównywać operatorem == – to bezpieczne, ponieważ wszystkie wartości są unikalne w obrębie klasy enum:
if (day == DayOfWeek.MONDAY) { ... } // OK!
Chociaż .equals() też działa, częściej używa się ==.
Błąd nr 3: złe nazwy elementów enum. Nie nazywaj elementów VALUE1, VALUE2, VALUE3 — za miesiąc nikt nie zrozumie, co to znaczy! Używaj mówiących nazw.
Błąd nr 4: używanie ordinal() w logice. Nie pisz tak:
if (day.ordinal() == 0) { ... } // Nie rób tak!
Kolejność elementów może się zmienić i wszystko się posypie. Używaj nazw!
GO TO FULL VERSION