CodeGym /Kursy /JAVA 25 SELF /Hierarchia wyjątków w Javie

Hierarchia wyjątków w Javie

JAVA 25 SELF
Poziom 24 , Lekcja 0
Dostępny

1. Klasa Throwable: korzeń wszystkich wyjątków

Teraz szczegółowo omówimy, jak działa system wyjątków w Javie: czym jest Throwable, czym różnią się Exception i Error, a także co oznacza „sprawdzane” i „niesprawdzane” wyjątki. To podstawa poprawnej obsługi błędów w twoich programach.

W Javie wszystkie wyjątki i błędy — to obiekty dziedziczące po klasie java.lang.Throwable.
Throwable — to „przodek” całej hierarchii obsługi problemów w Javie.

Schematycznie:

Throwable
├── Exception
└── Error

Throwable — klasa bazowa dla wszystkiego, co może zostać „wyrzucone” (throw) i „złapane” (catch) w Javie. Nie używa się jej bezpośrednio — służy jako podstawa dla bardziej konkretnych typów błędów.

Exception — dla „normalnych” błędów

Exception — klasa bazowa dla wszystkich wyjątków, które mogą wystąpić w programie i które można i należy obsługiwać. To „robocze” błędy: problemy z plikami, siecią, wejściem-wyjściem, błędami użytkownika itd. Większość twoich bloków try-catch będzie pracować właśnie z potomkami Exception.

Przykłady:

  • IOException — błąd podczas pracy z plikami lub siecią.
  • SQLException — błąd podczas pracy z bazą danych.
  • FileNotFoundException — plik nie został znaleziony.

Error — dla błędów krytycznych JVM

Error — klasa bazowa dla błędów, które występują na poziomie wirtualnej maszyny Javy (JVM). Zwykle są to krytyczne awarie, których program nie może i nie powinien obsługiwać. Jeśli pojawi się Error — najprawdopodobniej aplikacja nie będzie w stanie kontynuować pracy.

Przykłady:

  • OutOfMemoryError — brak pamięci.
  • StackOverflowError — przepełnienie stosu (np. z powodu nieskończonej rekursji).
  • NoClassDefFoundError — nie znaleziono wymaganej klasy.

Ważne:
Łapanie i obsługiwanie Error to prawie zawsze zły pomysł. To nie są błędy twojego programu, lecz awarie środowiska wykonawczego.

2. Checked vs Unchecked exceptions: co to oznacza?

W Javie wszystkie wyjątki dzielą się na dwie duże grupy:

Wyjątki sprawdzane (Checked)

Co to jest? Wyjątki, których kompilator wymaga obsłużenia lub jawnego przekazania dalej.

Kiedy występują? Zwykle są związane z zasobami zewnętrznymi: plikami, siecią, bazami danych, wejściem użytkownika.

Jak obsługiwać? Należy albo opakować kod w try-catch, albo dodać throws do sygnatury metody.

Przykłady: IOException, SQLException, FileNotFoundException

Przykład:

public void readFile(String path) throws IOException {
    FileReader reader = new FileReader(path); // może zgłosić IOException
    // ...
}

Jeśli nie obsłużysz lub nie przekażesz dalej — program się nie skompiluje!

Wyjątki niesprawdzane (Unchecked)

Co to jest? Wyjątki, które nie wymagają obowiązkowej obsługi przez kompilator.

Kiedy występują? Zwykle są to błędy w logice programu: dzielenie przez zero, wyjście poza zakres tablicy, odwołanie do null.

Jak obsługiwać? Można je łapać, ale nie jest to konieczne. Lepiej zapobiegać takim błędom poprzez odpowiednie sprawdzenia.

Gdzie w hierarchii? Wszystkie dziedziczą po RuntimeException.

Przykłady: NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException, ArithmeticException

Przykład:

int[] arr = {1, 2, 3};
System.out.println(arr[10]); // ArrayIndexOutOfBoundsException

Kompilator nie wymaga obsługi tego wyjątku — ale program zakończy działanie z błędem.

3. Cała hierarchia na jednym obrazku

graph TD
    Throwable --> Error
    Throwable --> Exception
    
    Exception --> RuntimeException
    Exception --> CheckedExceptions["(inne checked exceptions)"]
    
    Error --> OutOfMemoryError
    Error --> StackOverflowError
    
    RuntimeException --> NullPointerException
    RuntimeException --> IndexOutOfBoundsException
    RuntimeException --> IllegalArgumentException

    %% Style
    style Throwable fill:#ffa64d,color:#000
    style Exception fill:#ffa64d,color:#000
    style CheckedExceptions fill:#ffa64d,color:#000
    
    style Error fill:#ff4d4d,color:#fff
    style OutOfMemoryError fill:#ff4d4d,color:#fff
    style StackOverflowError fill:#ff4d4d,color:#fff
    
    style RuntimeException fill:#4dff88,color:#000
    style NullPointerException fill:#4dff88,color:#000
    style IndexOutOfBoundsException fill:#4dff88,color:#000
    style IllegalArgumentException fill:#4dff88,color:#000

Tabela: najważniejsze różnice

Grupa Klasa nadrzędna Wymaga obsługi? Przykłady
Checked Exception
Exception
Tak
IOException, SQLException
Unchecked
RuntimeException
Nie
NullPointerException, IndexOutOfBoundsException
Error
Error
Nie
OutOfMemoryError, StackOverflowError

4. Jak to wygląda w kodzie?

Wyjątek checked: przykład z plikami

import java.io.*;

public class FileDemo {
    public static void main(String[] args) {
        try {
            FileReader reader = new FileReader("nofile.txt"); // FileNotFoundException (checked)
            int data = reader.read();
            System.out.println(data);
            reader.close();
        } catch (IOException e) {
            System.out.println("Błąd podczas pracy z plikiem: " + e.getMessage());
        }
    }
}

Kompilator wymusi obsłużenie IOException!

Wyjątek unchecked: przykład z dzieleniem przez zero

public class ExceptionDemo {
    public static void main(String[] args) {
        int a = 10;
        int b = 0;
        int c = a / b; // ArithmeticException (unchecked)
        System.out.println("Wynik: " + c);
    }
}

Kompilator nie wymaga obsługi, ale program zakończy działanie z błędem.

5. Po co jest hierarchia wyjątków?

  • Elastyczność obsługi: Można łapać zarówno konkretne błędy (FileNotFoundException), jak i całe grupy (IOException lub Exception).
  • Wykorzystanie ponowne kodu: Można centralnie obsługiwać błędy jednego typu.
  • Czystość kodu: Logika główna nie jest zaśmiecana sprawdzeniami każdego drobiazgu.

Przykład:

try {
    // niebezpieczny kod
} catch (FileNotFoundException e) {
    System.out.println("Plik nie został znaleziony!");
} catch (IOException e) {
    System.out.println("Błąd wejścia/wyjścia!");
} catch (Exception e) {
    System.out.println("Coś poszło nie tak: " + e.getMessage());
}

6. Typowe błędy przy pracy z wyjątkami

Błąd nr 1: Ignorowanie wyjątków. Pisać catch (Exception e) {} — to zły pomysł! Tracisz informacje o przyczynie błędu.

Błąd nr 2: Łapiemy zbyt wiele. catch (Exception e) łapie wszystko jak leci, nawet to, czego się nie spodziewasz. Lepiej łapać tylko te wyjątki, które potrafisz obsłużyć.

Błąd nr 3: Łapiemy błędy (Error). Nie warto łapać Error, jeśli nie piszesz niskopoziomowego kodu. To problemy JVM, a nie twojego programu.

Błąd nr 4: Nie rozróżniamy checked i unchecked. Nie wszystkie wyjątki są takie same! Checked wymagają obsługi (Exception), unchecked — nie (RuntimeException i potomkowie).

Błąd nr 5: Nie dodajemy informacji do wyjątków. Jeśli tworzysz własne wyjątki — zawsze dodawaj informacyjny komunikat.

1
Zadanie
JAVA 25 SELF, poziom 24, lekcja 0
Niedostępne
Odkrywamy tajemnice wyjątków: hierarchia klas nadrzędnych
Odkrywamy tajemnice wyjątków: hierarchia klas nadrzędnych
1
Zadanie
JAVA 25 SELF, poziom 24, lekcja 0
Niedostępne
Kto jest najważniejszy? Różnica między wyjątkami a błędami
Kto jest najważniejszy? Różnica między wyjątkami a błędami
1
Zadanie
JAVA 25 SELF, poziom 24, lekcja 0
Niedostępne
System powiadomień: sprawdzane i niesprawdzane zagrożenia
System powiadomień: sprawdzane i niesprawdzane zagrożenia
1
Zadanie
JAVA 25 SELF, poziom 24, lekcja 0
Niedostępne
Robot-bibliotekarz i jego "plany ratunkowe"
Robot-bibliotekarz i jego "plany ratunkowe"
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION