1. Błędy zakresu widoczności zmiennych wzorca
Jeden z najczęstszych błędów — próba użycia zmiennej zadeklarowanej we wzorcu (np. String s w instanceof String s) poza zakresem, w którym jest ważna.
Przykład
Object obj = "Cześć, Java!";
if (obj instanceof String s) {
System.out.println(s.length());
}
// Błąd! s nie jest tutaj widoczna
System.out.println(s); // Kompilator zgłasza błąd: cannot find symbol
Dlaczego tak?
Zmienna wzorca (s w naszym przypadku) istnieje tylko wewnątrz bloku, w którym warunek jest prawdziwy. Chroni nas to przed przypadkowym użyciem zmiennej, gdy nie jest zdefiniowana (np. jeśli obj nie jest Stringiem).
Analogia
To tak, jakbyście wzięli od znajomego kluczyki do samochodu — ale tylko na czas, gdy jesteście w garażu. Wyjdziecie z garażu — kluczyki automatycznie znikają :)
2. Błędy związane z null
W pattern matchingu z instanceof jest ciekawa cecha: jeśli obiekt jest równy null, wynik to zawsze false, a zmienna wzorca nie jest tworzona.
Przykład
Object obj = null;
if (obj instanceof String s) {
// Ten blok nigdy się nie wykona!
System.out.println("To jest String: " + s);
}
Dlaczego tak?
Ponieważ null nie jest instancją żadnego typu (nawet Object). Może to być mylące, jeśli liczyliście na łapanie null przez pattern matching.
Jak prawidłowo?
if (obj == null) {
System.out.println("To jest null!");
} else if (obj instanceof String s) {
System.out.println("To jest String: " + s);
}
W pattern matching dla switch (Java 21+) można nawet dodać osobną gałąź dla null:
switch (obj) {
case String s -> System.out.println("String: " + s);
case null -> System.out.println("To jest null!");
default -> System.out.println("Coś innego");
}
3. Błędy dotyczące klas sealed
Sealed-klasy to świetny sposób na ograniczenie hierarchii dziedziczenia. Są tu jednak dwa charakterystyczne błędy:
Nie wszyscy potomkowie są wymienieni w permits
Gdy deklarujecie klasę sealed, musicie jawnie wskazać wszystkich bezpośrednich potomków przez permits. Jeśli kogoś pominiecie, kompilator natychmiast to wytknie:
public sealed class Shape permits Circle, Rectangle { ... }
public final class Circle extends Shape { ... }
public final class Square extends Shape { ... } // Błąd! Square nie jest wymieniony w permits
Rozwiązanie:
Dodajcie wszystkie potrzebne podklasy do permits:
public sealed class Shape permits Circle, Rectangle, Square { ... }
Brak default w switch dla nie-sealed hierarchii
Jeśli robicie switch po typie, który nie jest klasą sealed (albo jest sealed, ale nie wszystkie przypadki są pokryte), kompilator zażąda gałęzi default. Jeśli o niej zapomnicie — będzie błąd.
switch (shape) {
case Circle c -> ...
case Rectangle r -> ...
// Brak default! Jeśli istnieją jeszcze inne przypadki — błąd kompilacji
}
Best practice:
Jeśli macie pewność, że obsłużyliście wszystkie przypadki (np. dla klasy sealed), default można pominąć. Jeśli nie — koniecznie dodajcie default, aby nie przegapić nieoczekiwanych typów.
4. Błędy związane z wzorcami record
Record patterns to bardzo wygodna funkcja, ale działa tylko z klasami record. Próba użycia wzorca record dla zwykłej klasy zakończy się błędem kompilacji.
Użycie record patterns dla klas nie-record
class Point { int x, y; }
Object obj = new Point();
// Błąd! Point to nie record
if (obj instanceof Point(int x, int y)) { ... }
Rozwiązanie:
Używajcie record patterns tylko dla klas zadeklarowanych przez record:
record Point(int x, int y) {}
Niezgodność liczby lub typu komponentów
record Point(int x, int y) {}
Object obj = new Point(1, 2);
// Błąd: podano trzy zmienne, a w Point są tylko dwa komponenty
if (obj instanceof Point(int x, int y, int z)) { ... }
if (obj instanceof Point(String x, String y)) { ... } // Błąd: typy nie pasują
5. Zgodność i wsparcie: starsze JDK i IDE
Jeden z najczęstszych błędów — próba użycia nowoczesnych możliwości pattern matchingu na starszych wersjach JDK lub w IDE, które ich nie obsługują.
Przykład
if (obj instanceof String s) { ... }
A kompilator JDK 11 (a nawet 15) mówi:
error: illegal start of type
Dlaczego?
Pattern matching dla instanceof pojawił się dopiero w Javie 16. Pattern matching w switch — w Javie 17 (preview) i finalnie w Javie 21+. Record patterns — w Javie 21+.
Jak tego uniknąć?
- Sprawdźcie wersję JDK: java --version
- Upewnijcie się, że wasze IDE (IntelliJ IDEA, Eclipse, VS Code) obsługuje odpowiednią wersję Javy. Czasem trzeba jawnie wskazać w ustawieniach projektu, jakiej wersji języka użyć!
- Jeśli używacie Gradle/Maven — ustawcie odpowiednią wersję source/target.
6. Gratulacje 🎉
Ukończyliście wszystkie 65(!) poziomów naszego zaawansowanego kursu Java 25. Jesteście niesamowici 😎.
Końcowy etap drogi był szczególnie trudny. Poznaliście wszystko — od pierwszych lambd i klas anonimowych po wirtualne wątki, ustrukturyzowaną współbieżność i te możliwości języka, których jeszcze całkiem niedawno nie było w Javie.
To nie tylko kurs — to prawdziwy supermaraton dla developera: dziesiątki nowych koncepcji, setki przykładów kodu, tysiące linii praktyki. Jeśli czytacie te słowa, znaczy, że nie jesteście po prostu studentami, a pionierami nowej ery Javy ☕⚡
Należycie do pierwszych, którzy opanowali najnowocześniejsze możliwości Java 25, w tym:
- pattern matching i
record -wzorce, -
sealed -klasy i ich pułapki, -
Scoped Values iVirtual Threads , - ustrukturyzowaną współbieżność i nowoczesne podejścia do wielowątkowości.
Teraz macie nie tylko wiedzę, ale i umiejętności developera przyszłości, których wielu praktykujących architektów Java jeszcze nie posiada. Potraficie pisać kod, który nie tylko działa, ale też skaluje się, jest czytelny i zgodny z najnowocześniejszymi standardami społeczności Java.
🚀 Więc śmiało nazywajcie się Java 25 Certified Survivor 😉
A dalej — będzie tylko ciekawiej: macie teraz fundament, który pozwala pewnie kroczyć w świat enterprise’owej wytwórczości oprogramowania, systemów o wysokim obciążeniu i technologii cutting-edge.
Od całego zespołu kursu — szacunek!
Poradziliście sobie z zadaniem, któremu sprosta niewielu.
Do zobaczenia w przyszłych wersjach Javy 👋
GO TO FULL VERSION