Java HR: Wyjątki – Exception i Error, checked i unchecked
Tym razem wyjątkowy artykuł – wyjątki każdy programista zna i zapewne używa regularnie, jednak czym różnią się w Javie poszczególne ich rodzaje?
Czym jest wyjątek
Mechanizm wyjątków służy do obsługi błędów, które mogą wystąpić w czasie przebiegu programu. Jak sama nazwa wskazuje, wyjątek (exception) to odbiegnięcie od standardowego, zaplanowanego przebiegu programu. W Javie wyjątek reprezentowany jest przez obiekt klasy Throwable, który posiada zbiór pól i metod przydatnych do jego późniejszej analizy – oprócz swojej nazwy przechowuje takie informacje jak opis błędu (message) oraz stack trace, czyli zapis stosu wywołań, reprezentujący obecny stan programu.
Podział wyjątków w Javie
–Throwable
——Error
——Exception
———-Poszczególne wyjątki
———-RuntimeException
————–Poszczególne wyjątki
Wyjątki zgromadzone są w 3 podstawowych grupach.
Klasa Throwable dzieli się na dwie inne, dziedziczące po niej klasy – Error i Exception. Po Exception z kolei dziedziczy RuntimeException oraz już bezpośrednio cały szereg poszczególnych wyjątków, takich jak IOException czy SQLException.
- Error – obiekty rzucane automatycznie przez JVM, w momencie gdy program natrafi na krytyczny błąd w środowisku wykonawczym, którego nie można obsłużyć i z którego nie można programu już odratować.
Przykłady: OutOfMemoryError, StackOverflowError - Exception – „klasyczne”, najzwyklejsze wyjątki. Konieczna jest ich obsługa (patrz niżej) i to najczęściej tę klasę będziemy rozszerzać tworząc własną klasę Throwable.
Najczęściej dotyczą sytuacji, w której jest duża szansa, że błąd może wystąpić na skutek jakiejś zewnętrznej przyczyny – np. w systemie gospodarza zabraknie odpowiedniego pliku lub nie uda się połączyć z serwerem. Program musi być koniecznie gotowy na taką ewentualność.
Przykłady: IOException, SQLException - RuntimeException – co prawda dziedziczy po klasie Exception, jednak obiekty tej klasy są traktowane w szczególny sposób. Nie jest konieczna ich obsługa, lecz czasami może to się okazać dobrym pomysłem. Zwłaszcza, gdy piszemy jakąś bibliotekę lub API i nie jesteśmy pewni czy będą one używane w bezpieczny sposób przez innych programistów. Najczęściej dotyczą problemów w samym kodzie programu, spowodowanych przez programistę – np. referencja nieoczekiwanie będzie nullem, iteracja po tablicy przekroczy jej rozmiar, funkcja podzieli coś przez zero.
Przykłady: NullPointerException, IndexOutOfBoundsException
Checked vs Unchecked
- Exception -> checked
- Error, RuntimeException -> unchecked
Checked oznacza tyle, że wyjątki te są sprawdzane na etapie kompilacji kodu. Jeśli ich w żaden sposób nie obsłużymy, to programu nie będziemy mogli wykonać. Jest to mechanizm wspierający programistę, dzięki temu zawsze z pełną świadomością decyduje w jaki sposób program ma przebiec dalej po wystąpieniu takiego błędu – nie powinny one przerywać działania programu.
Naturalnie mechanizm ten nie występuje przy Errorach (program musi i tak zostać przerwany) oraz RuntimeException (zwykle nie ma sensu ich obsługiwać, poza tym nie da się przewidzieć w którym momencie taki wyjątek może wystąpić).
Obsługa wyjątku
Co dzieje się z wyjątkiem, gdy go nie obsłużymy?
Obiekt jest tworzony, JVM przechodzi przez stos wywołań (call stack) i sprawdza kolejno w każdej metodzie czy dana klasa wyjątku jest łapana w bloku catch (exception handler). Jeśli dotrze aż do metody main to uruchomi się default exception handler, który drukuje do konsoli opis wyjątku, stack trace i działanie programu zostaje nagle przerwane.
Dlatego, żeby wyjątek obsłużyć, musimy posłużyć się mechanizmem try-catch-finally (więcej w atykule: Java HR: final, finally i finalize).
Przy try możemy dopisać dowolną liczbę bloków catch – od najbardziej szczegółowego do najmniej (dlatego, że gdy wyjątek zostanie złapany w jednym z bloków, program nie dotrze już do kolejnych).
Jeśli nie chcemy w danej metodzie wyjątku bezpośrednio obsługiwać (a jest on checked), trzeba do deklaracji metody dopisać keyword throws i klasę wyjątku występującego w jej wnętrzu.
Informatyk, programista. Obecnie Java Developer (Web Fullstack), właściciel studia Berrygames oraz prezes koła TK Games na Politechnice Wrocławskiej.