Sobes.tech
Junior

Jak obsługiwać błędy w Java i jak z nimi pracować?

sobes.tech AI

Odpowiedź od AI

W Javie błędy są obsługiwane za pomocą mechanizmu wyjątków. Wyjątki to zdarzenia, które zakłócają normalny przebieg wykonywania programu. Istnieją dwa typy wyjątków: Sprawdzane (Checked Exceptions) i Nie sprawdzane (Unchecked Exceptions).

Sprawdzane wyjątki:

  • Dziedziczą z java.lang.Exception (z wyjątkiem RuntimeException).
  • Muszą być obsłużone (za pomocą try-catch) lub zadeklarowane w sygnaturze metody (za pomocą throws).
  • Reprezentują błędy, które mogą wystąpić w normalnych warunkach (np. IOException, FileNotFoundException).

Nie sprawdzane wyjątki:

  • Dziedziczą z java.lang.RuntimeException lub java.lang.Error.
  • Nie wymagają obowiązkowego obsługi ani deklaracji.
  • Reprezentują błędy, które często wskazują na błędy logiczne w kodzie lub nieprawidłowe stany środowiska wykonawczego (np. NullPointerException, ArrayIndexOutOfBoundsException).

Obsługa wyjątków:

Do obsługi wyjątków używa się bloków try-catch-finally:

  • try: blok kodu, który może wygenerować wyjątek.
  • catch: blok kodu, który jest wykonywany, jeśli w try wystąpi wyjątek określonego typu. Można mieć kilka catch dla różnych typów wyjątków.
  • finally: blok kodu, który jest wykonywany niezależnie od tego, czy wystąpił wyjątek, czy nie. Często używany do zwalniania zasobów (np. zamykania plików, połączeń).
try {
    // Kod, który może wywołać wyjątek
    int result = 10 / 0; // Przykład: ArithmeticException
} catch (ArithmeticException e) {
    // Obsługa ArithmeticException
    System.err.println("Błąd dzielenia przez zero: " + e.getMessage());
    // Można logować błąd, wyświetlać komunikat użytkownikowi itp.
} catch (Exception e) {
    // Obsługa dowolnego innego wyjątku
    System.err.println("Wystąpił ogólny błąd: " + e.getMessage());
} finally {
    // Kod, który zawsze się wykona
    System.out.println("Blok finally został wykonany.");
}

Propagacja wyjątków:

Metoda może deklarować, że może wygenerować określony wyjątek, używając słowa kluczowego throws:

public void readFile(String filePath) throws FileNotFoundException, IOException {
    // Kod odczytu pliku
    // Jeśli plik nie zostanie znaleziony, może zostać wyrzucony `FileNotFoundException` (podklasa `IOException`)
    FileReader fr = new FileReader(filePath);
    // Jeśli wystąpi błąd wejścia/wyjścia, może zostać wyrzucony `IOException`
    // ...
}

Wywołująca metoda musi obsłużyć ten wyjątek (try-catch) lub również zadeklarować, że go propaguje.

Tworzenie własnych wyjątków:

Można tworzyć własne klasy wyjątków dziedziczące po Exception (dla Sprawdzanych Wyjątków) lub RuntimeException (dla Nie sprawdzanych Wyjątków).

public class MyCustomException extends Exception {
    public MyCustomException(String message) {
        super(message);
    }
}

Użycie:

public void processData(int value) throws MyCustomException {
    if (value < 0) {
        throw new MyCustomException("Wartość nie może być ujemna");
    }
    // Przetwarzanie danych
}

Główne klasy wyjątków (hierarchia):

  • java.lang.Throwable (klasa bazowa dla wszystkich błędów i wyjątków)
    • java.lang.Error (dla poważnych problemów, które zwykle nie są obsługiwane przez program, np. OutOfMemoryError)
    • java.lang.Exception (dla wyjątków, które program może obsłużyć)
      • java.lang.RuntimeException (Nie sprawdzane wyjątki)
        • NullPointerException
        • ArrayIndexOutOfBoundsException
        • ArithmeticException
        • itd.
      • Inne podklasy Exception (Sprawdzane wyjątki)
        • IOException
        • FileNotFoundException
        • SQLException
        • itd.

Praca z błędami wymaga zrozumienia tej hierarchii, wyboru odpowiedniego typu wyjątku (przy tworzeniu własnych), skutecznego użycia try-catch-finally do obsługi i propagacji wyjątków, a także logowania błędów do celów debugowania.