W Javie wyjątki dzielą się na checked (sprawdzane) i unchecked (niezależne).
Exception, ale nie od RuntimeException. Kompilator wymaga ich jawnej obsługi za pomocą try-catch lub zadeklarowania w throws.RuntimeException. Kompilator nie wymaga ich obowiązkowej obsługi.public void readFile(String file) throws IOException { /* ... */ } // checked public void divide(int a, int b) { int res = a/b; } // unchecked (ArithmeticException)
Główna subtelność — checked exceptions są używane do oczekiwanych, naprawialnych sytuacji (np. błędy wejścia-wyjścia), podczas gdy unchecked — do błędów w logice programowania lub sytuacji krytycznych, z których nie można się odzyskać (np. NullPointerException).
Pytanie: Czy trzeba obsłużyć lub zadeklarować w throws unchecked exception, jeśli twój metod może je wyrzucić?
Odpowiedź: Nie. Kompilator nie wymaga sprawdzania lub deklarowania nieodwracalnych (unchecked) wyjątków. Ich obsługa jest Twoją decyzją; można użyć try-catch, ale częściej — pozwolić im „upaść” aż do globalnego handlera.
public void foo() { throw new IllegalArgumentException(); } // Nie wymaga obsługi ani deklaracji
Historia
W projekcie API bankowego przy obsłudze błędów wejścia-wyjścia rzucano
RuntimeExceptionzamiast checked. W rezultacie klienci nie byli zmuszeni ich obsługiwać, co prowadziło do niewłaściwego działania przy utracie połączenia z serwerem, a aplikacja „upadała” bez informowania użytkownika.
Historia
Programista zadeklarował nadmiar
throws Exceptionw sygnaturze metod (np. bazy danych), przez co wszystkie używane metody wyżej były zmuszone do try-catch lub też throws. To zanieczyściło kod, pogorszyło czytelność i utrudniło refaktoryzację.
Historia
W jednej z mikroserwisów łapano wszystkie wyjątki za pomocą ogólnego
catch (Exception e). To przechwytywało również unchecked exception’y (np.NullPointerException), co prowadziło do „cichego” ignorowania krytycznych błędów — serwis działał z niepoprawnymi danymi.