Switch w Javie od break do pattern matching

Przykłady kodu Java pokazujące składnię switch: wyrażenia i instrukcje, z użyciem składni dwukropka i strzałki.

Napisano przez

Tymoteusz Sobczak

Opublikowano

18 wrz 2026

Spis treści

Gdy aplikacja ma zareagować inaczej na status zamówienia, rolę użytkownika albo wybraną opcję menu, seria instrukcji if szybko zaczyna przypominać labirynt. Konstrukcja switch w Javie, często opisywana skrótowo jako java switch, porządkuje takie scenariusze i pozwala zapisać je znacznie czytelniej. Pokażę klasyczną składnię, nowoczesne wyrażenia switch, obsługę tekstu i enumów, pattern matching oraz błędy, które najczęściej psują działanie kodu.

Najważniejsze zasady switch w Javie w jednym miejscu

  • Switch wybiera jedną z wielu ścieżek na podstawie wartości wyrażenia.
  • break zatrzymuje klasyczne przechodzenie do kolejnych przypadków.
  • Składnia case ... -> eliminuje przypadkowe przejście między gałęziami.
  • Switch expression zwraca wartość i dobrze pasuje do przypisywania wyniku.
  • W Javie 21 i nowszej można używać pattern matchingu oraz obsługi null.

Kod Java z sugestią zamiany if na java switch. Widoczny jest kod obsługujący różne typy kart, np. SILVER, GOLD, PLATINUM.

Switch w Javie w praktyce i podstawowa składnia

Instrukcja switch sprawdza wartość jednego wyrażenia, a potem uruchamia kod przypisany do pasującego przypadku. Najlepiej działa wtedy, gdy porównujemy jedną zmienną z kilkoma konkretnymi wartościami, na przykład statusem zamówienia albo nazwą dnia tygodnia.

int punkty = 0;
String poziom = "srebro";

switch (poziom) {
    case "brąz":
        punkty = 10;
        break;
    case "srebro":
        punkty = 25;
        break;
    case "złoto":
        punkty = 50;
        break;
    default:
        punkty = 0;
}

Każdy blok zaczyna się od etykiety case, a default obsługuje wszystkie wartości, których nie wymieniono wcześniej. W tym przykładzie najważniejsze jest break, ponieważ kończy wykonanie bieżącej gałęzi. Bez niego program przeszedłby do kolejnego case, nawet jeśli nie powinien.

Klasyczna forma nadal jest poprawna i spotyka się ją w starszych projektach. W nowym kodzie najczęściej wybieram jednak zapis z grotami, ponieważ ogranicza liczbę miejsc, w których można popełnić błąd.

Case, break i default czyli skąd bierze się fall-through

Fall-through oznacza automatyczne przejście z jednego przypadku do następnego. Czasem jest zamierzone, na przykład gdy kilka wartości ma wywołać tę samą logikę, ale przypadkowy brak break potrafi stworzyć trudny do zauważenia błąd.

switch (typKonta) {
    case "admin":
    case "moderator":
        System.out.println("Dostęp do panelu");
        break;
    case "użytkownik":
        System.out.println("Dostęp podstawowy");
        break;
    default:
        System.out.println("Brak uprawnień");
}

Połączenie dwóch etykiet bez kodu pomiędzy nimi jest czytelne i bezpieczne. Zarówno admin, jak i moderator trafiają do tego samego fragmentu. Z mojego doświadczenia wynika, że taki zapis jest lepszy niż kopiowanie identycznych instrukcji do kilku gałęzi.

W praktyce default powinien być świadomą decyzją, a nie automatycznym dodatkiem. Przy danych pochodzących z formularza, pliku lub API zwykle warto przewidzieć nieznaną wartość. Przy kompletnym enumie można czasem polegać na pełnym wyliczeniu jego stałych, ale wtedy zmiana modelu danych może wymagać ponownego przejrzenia kodu.

Warto też pamiętać, że switch nie zastępuje każdego warunku. Nie jest dobrym narzędziem do sprawdzania przedziałów, takich jak „wiek od 18 do 25 lat”, ani złożonych zależności logicznych. W takich przypadkach czytelniejsze będzie if, metoda pomocnicza albo osobna reguła biznesowa.

Switch expression zwraca wartość i skraca kod

Od Javy 14 wyrażenie switch może zwracać wartość. To ważna różnica względem klasycznej instrukcji, ponieważ wynik można od razu przypisać do zmiennej, zwrócić z metody albo wykorzystać w innym wyrażeniu.

String komunikat = switch (status) {
    case "NOWE" -> "Zamówienie przyjęte";
    case "WYSŁANE" -> "Przesyłka jest w drodze";
    case "ZREALIZOWANE" -> "Zamówienie zakończone";
    default -> "Nieznany status";
};

Składnia case ... -> nie przechodzi automatycznie do kolejnych przypadków. Dzięki temu nie trzeba dodawać break, a intencja kodu jest widoczna od razu. Właśnie ten zapis polecam jako domyślny przy nowych fragmentach aplikacji.

Jeżeli jedna gałąź wymaga kilku instrukcji, można użyć bloku i słowa yield. Służy ono do przekazania wartości z konkretnej gałęzi wyrażenia.

int rabat = switch (poziom) {
    case "złoto" -> 20;
    case "srebro" -> 10;
    case "brąz" -> 5;
    default -> {
        System.out.println("Brak programu lojalnościowego");
        yield 0;
    }
};

W tym miejscu początkujący często mylą yield z return. Yield zwraca wartość z wyrażenia switch, ale nie kończy działania całej metody. To drobna różnica, która ma znaczenie przy bardziej rozbudowanych metodach.

String, enum i liczby w instrukcji switch

W codziennym kodzie najczęściej przełączam po wartościach typu int, String oraz po stałych enumów. Każdy wariant ma inne zastosowanie, dlatego typ zmiennej powinien wynikać z modelu danych, a nie z wygody pojedynczego fragmentu.

Typ Przykładowe zastosowanie Na co uważać
int kody, poziomy, numery opcji nieczytelne „magiczne liczby”
String statusy z API lub formularza literówki i różnice w wielkości liter
enum zamknięty zestaw stanów zmiana enumu może wymagać uzupełnienia switch

Enum zwykle wygrywa ze stringiem tam, gdzie lista wartości jest zamknięta. Zamiast porównywać tekst "WYSŁANE", można zdefiniować Status.WYSLANE i otrzymać lepsze wsparcie kompilatora oraz mniejsze ryzyko literówki.

enum Status {
    NOWE, WYSŁANE, ZREALIZOWANE
}

String etykieta(Status status) {
    return switch (status) {
        case NOWE -> "Nowe";
        case WYSŁANE -> "Wysłane";
        case ZREALIZOWANE -> "Zrealizowane";
    };
}

Przy tekście trzeba natomiast pamiętać, że porównanie jest dokładne. Wartość "nowe" nie pasuje do "NOWE", a dodatkowa spacja również zmieni wynik. Przy danych od użytkownika najpierw normalizuję tekst, na przykład przez trim() i ujednolicenie wielkości liter.

Pattern matching pozwala reagować na typ obiektu

W Javie 21 pattern matching dla switch stał się stabilnym elementem języka. Pozwala sprawdzić nie tylko konkretną wartość, ale także typ obiektu i od razu uzyskać zmienną właściwego typu.

String opisz(Object dane) {
    return switch (dane) {
        case null -> "Brak danych";
        case Integer liczba when liczba > 0 -> "Dodatnia liczba";
        case Integer liczba -> "Liczba niedodatnia";
        case String tekst when tekst.isBlank() -> "Pusty tekst";
        case String tekst -> "Tekst o długości " + tekst.length();
        default -> "Inny obiekt";
    };
}

Zmienna liczba jest dostępna jako Integer, a tekst jako String. Warunek when doprecyzowuje dopasowanie, więc można rozdzielić dodatnie liczby od pozostałych. To rozwiązanie jest czytelniejsze niż seria instanceof i ręczne rzutowania.

Obsługa null wymaga świadomego podejścia. W tradycyjnym switch przekazanie wartości null zwykle kończy się wyjątkiem NullPointerException. W pattern matchingu można jawnie dodać case null, ale nie powinno się używać go jako sposobu na ukrywanie błędów w danych.

Przy projektach działających na starszej wersji Javy trzeba sprawdzić wersję kompilatora i ustawienia środowiska. Kod korzystający z pattern matchingu nie będzie automatycznie działał w projekcie skonfigurowanym na Javę 17, jeśli nie zostanie odpowiednio dostosowany.

Najczęstsze błędy i wybór między switch a if

Najbardziej typowy problem to brak break w starej składni. Drugim jest brak obsługi wartości spoza oczekiwanego zestawu, szczególnie gdy dane przychodzą z zewnętrznego systemu. Trzeci błąd polega na mieszaniu instrukcji i wyrażeń, przez co kod próbuje używać yield albo wartości zwracanej tam, gdzie nie ma takiej potrzeby.

Sytuacja Lepszy wybór Dlaczego
Kilka konkretnych wartości jednej zmiennej switch kod jest uporządkowany według przypadków
Przedziały liczbowe if łatwiej zapisać zakresy i nierówności
Złożone warunki logiczne if lub metoda reguł switch nie powinien ukrywać rozbudowanej logiki
Typy obiektów i kilka wariantów danych pattern matching typ i warunek można obsłużyć w jednej konstrukcji

Jeśli używam klasycznego zapisu z dwukropkami, od razu sprawdzam, czy każde przejście ma uzasadnienie. W nowym kodzie preferuję reguły z grotami, bo kompilator i sama struktura programu pomagają uniknąć fall-through.

Nie warto też wrzucać całej logiki biznesowej do jednej instrukcji. Gdy gałęzie zaczynają mieć po kilkadziesiąt linii, lepiej wywołać osobne metody. Dzięki temu switch pozostaje mapą decyzji, a nie miejscem, w którym trzeba szukać całego procesu obsługi zamówienia.

Mały test, który szybko utrwala switch

Najlepsze ćwiczenie polega na napisaniu metody, która dla statusu zamówienia zwraca komunikat, a dla nieznanej wartości sygnalizuje problem. Najpierw warto zrobić wersję z klasycznym break, potem przepisać ją na wyrażenie z grotami i porównać czytelność.

  • Dodaj obsługę trzech statusów.
  • Połącz dwa statusy w jedną gałąź.
  • Sprawdź działanie dla wartości spoza listy.
  • Przepisz rozwiązanie na switch expression.
  • Dodaj test dla null, jeśli korzystasz z pattern matchingu.

Moja praktyczna zasada jest prosta. Używaj switch do jasnego wyboru między konkretnymi wariantami, wybieraj zapis z -> w nowym kodzie, a przedziały i złożone warunki zostaw instrukcjom if. Taki podział daje kod łatwiejszy do czytania, testowania i rozwijania wraz z aplikacją.

FAQ - Najczęstsze pytania

Switch sprawdza się przy wyborze między kilkoma konkretnymi wartościami jednej zmiennej, na przykład statusem zamówienia lub typem konta. Instrukcja if będzie czytelniejsza przy przedziałach liczbowych, nierównościach i złożonych warunkach logicznych.

Klasyczna instrukcja switch wykonuje kod w wybranej gałęzi i zwykle wymaga break, aby zapobiec fall-through. Switch expression zwraca wartość, korzysta ze składni case ... -> i nie przechodzi automatycznie do kolejnych przypadków. Gdy gałąź zawiera kilka instrukcji, wartość przekazuje się za pomocą yield.

Porównanie Stringów jest dokładne, więc różnica w wielkości liter lub dodatkowa spacja może spowodować brak dopasowania. Dane od użytkownika warto wcześniej znormalizować przez trim() i ujednolicenie wielkości liter. Enum jest lepszym wyborem, gdy lista wartości jest zamknięta, ponieważ ogranicza ryzyko literówek i zapewnia wsparcie kompilatora.

Pattern matching dla switch jest stabilny w Javie 21 i nowszej. Pozwala dopasowywać typ obiektu, używać warunku when oraz jawnie obsługiwać case null. Kod korzystający z tych funkcji wymaga odpowiednio skonfigurowanego kompilatora i nie zadziała automatycznie w projekcie ustawionym na starszą wersję Javy.

Oceń artykuł

Ocena: 0.00 Liczba głosów: 0

Tagi:

java switch pattern matching enumy

Udostępnij artykuł

Tymoteusz Sobczak

Tymoteusz Sobczak

Nazywam się Tymoteusz Sobczak i od 7 lat zajmuję się programowaniem webowym. Moje zainteresowanie tą dziedziną zaczęło się od prostych projektów, które realizowałem w wolnym czasie. Z czasem odkryłem, jak fascynujące jest tworzenie aplikacji, które mogą ułatwiać życie innym. Chętnie dzielę się swoją wiedzą, pomagając czytelnikom zrozumieć złożone zagadnienia związane z programowaniem, od podstawowych technik po bardziej zaawansowane rozwiązania. Pisząc na temat programowania, staram się dostarczać informacje, które są nie tylko użyteczne, ale także zrozumiałe. Zawsze dokładam starań, aby moje źródła były wiarygodne, a treści aktualne. Lubię upraszczać trudne tematy i organizować wiedzę w sposób, który ułatwia naukę. Wierzę, że każdy, kto ma chęci, może stać się dobrym programistą, a ja jestem tutaj, aby wskazać drogę.

Napisz komentarz