1. Rodzaje wyjątków
Wszystkie wyjątki są podzielone na 4 typy, które w rzeczywistości są klasami dziedziczonymi po sobie.
KlasaThrowable
Najbardziej podstawową klasą dla wszystkich wyjątków jest klasa Throwable
. Klasa Throwable
zawiera kod, który zapisuje bieżący ślad stosu wywołań funkcji do tablicy. Co to jest ślad stosu wywołań, omówimy nieco później.
Do instrukcji throw można przekazać tylko obiekt klasy pochodnej Throwable
. I choć teoretycznie możliwe jest napisanie kodu widoku throw new Throwable();
, to zwykle nikt tego nie robi. Głównym celem istnienia klasy Throwable
jest jedna klasa przodków dla wszystkich wyjątków.
KlasaError
Następną klasą wyjątków jest klasa Error
- bezpośredni potomek klasy Throwable
. Obiekty typu Error
(i jego klasy potomne) są tworzone przez maszynę Java w przypadku poważnych problemów . Na przykład awaria, brak pamięci itp.
Zwykle jako programista nie możesz nic zrobić , gdy program zawiera błąd typu Error
: błąd jest zbyt poważny. Wszystko, co możesz zrobić, to powiadomić użytkownika, że program się zawiesza, lub zapisać wszystkie znane informacje o błędzie do dziennika programu.
KlasaException
Wyjątki typu Exception
( i RuntimeException
) to typowe błędy występujące podczas działania wielu metod. Celem każdego zgłoszonego wyjątku jest wychwycenie go przez blok, catch
który wie, co zrobić w tej sytuacji.
Gdy metoda nie może wykonać swojego zadania z jakiegoś powodu, musi natychmiast powiadomić metodę wywołującą, zgłaszając wyjątek odpowiedniego typu.
Innymi słowy, jeśli jakaś zmienna okazała się równa null
, metoda wyrzuci NullPointerException
, jeśli do metody zostały przekazane błędne argumenty, wyrzuci InvalidArgumentException
, jeśli metoda przypadkowo miała dzielenie przez zero — ArithmeticException
.
KlasaRuntimeException
RuntimeExceptions
jest rodzajem (podzbiorem) wyjątków Exceptions
. Można nawet powiedzieć, że RuntimeException
jest to lżejsza wersja zwykłych wyjątków ( Exception
): na takie wyjątki nakłada się mniej wymagań i ograniczeń.
Dowiedz się więcej Exception
o różnicyRuntimeException
2. Sprawdzone wyjątki: Throws
, sprawdzone wyjątki
Wszystkie wyjątki w Javie są podzielone na 2 kategorie - zaznaczone ( zaznaczone ) i niezaznaczone ( niezaznaczone ).
Wszystkie wyjątki odziedziczone po klasach RuntimeException
i Error
są uważane za niesprawdzone wyjątki , wszystkie inne są uważane za sprawdzone wyjątki .
20 lat po wprowadzeniu sprawdzonych wyjątków prawie wszyscy programiści Javy uważają to za błąd. 95% wszystkich wyjątków w popularnych nowoczesnych frameworkach nie jest zaznaczonych. Ten sam język C#, który prawie skopiował czystą Javę, nie dodał sprawdzonych wyjątków .
Jaka jest główna różnica między sprawdzonymi wyjątkami a niezaznaczonymi ?
Istnieją dodatkowe wymagania dotyczące sprawdzanych wyjątków . Brzmią tak.
Wymóg 1
Jeśli metoda zgłasza sprawdzony wyjątek , musi zawierać typ tego wyjątku w swoim nagłówku (sygnatura metody). Aby wszystkie metody wywołujące tę metodę wiedziały, że może w niej wystąpić taki „ważny wyjątek”.
Sprawdzone wyjątki muszą być określone po parametrach metody po słowie kluczowym throws
(nie mylić z throw
). Wygląda to mniej więcej tak:
type method (parameters) throws exception
Przykład:
sprawdzony wyjątek | niesprawdzony wyjątek |
---|---|
|
|
W przykładzie po prawej stronie nasz kod zgłasza niesprawdzony wyjątek — nie są wymagane żadne dalsze działania. W przykładzie po lewej stronie metoda zgłasza sprawdzony wyjątek , więc do sygnatury metody dodano słowo kluczowe throws
i określono typ wyjątku.
Jeśli metoda planuje zgłosić wiele sprawdzonych wyjątków , wszystkie z nich muszą być określone po słowie kluczowym, throws
oddzielone przecinkami. Kolejność jest nieważna. Przykład:
public void calculate(int n) throws Exception, IOException
{
if (n == 0)
throw new Exception("n is null!");
if (n == 1)
throw new IOException("n is 1");
}
Wymóg 2
Jeśli wywołasz metodę, która ma sprawdzone wyjątki w swojej sygnaturze , nie możesz zignorować tego faktu.
Musisz albo przechwycić wszystkie te wyjątki, dodając bloki catch
dla każdego z nich, albo dodać je dothrows
swojej metody.
Wydaje się, że mówimy sobie: te wyjątki są tak ważne, że koniecznie musimy je złapać. A jeśli nie wiemy jak je złapać, musimy powiadomić tych, którzy wywołają naszą metodę, że takie wyjątki mogą w niej wystąpić.
Przykład:
Wyobraź sobie, że piszemy metodę, która ma stworzyć świat zamieszkały przez ludzi. Początkowa liczba osób jest przekazywana jako parametr. Następnie musimy dodać wyjątki, jeśli jest zbyt mało osób.
Tworzenie Ziemi | Notatka |
---|---|
|
Metoda potencjalnie zgłasza dwa sprawdzone wyjątki :
|
To wywołanie metody można obsłużyć na 3 sposoby:
1. Nie wychwytuj pojawiających się wyjątków
Dzieje się tak najczęściej, gdy metoda nie wie, jak prawidłowo poradzić sobie z tą sytuacją.
Kod | Notatka |
---|---|
|
Metoda wywołująca nie wyłapuje wyjątków i jest zmuszona informować o nich innych: dodaje je do siebie wthrows |
2. Złap kilka wyjątków
Przetwarzamy błędy zrozumiałe, niezrozumiałe - wrzucamy je do metody wywołującej. Aby to zrobić, dodaj ich imię do rzutów:
Kod | Notatka |
---|---|
|
Metoda wywołująca przechwytuje tylko jeden sprawdzony wyjątek - LonelyWorldException , musi dodać drugi do swojej sygnatury: określ po słowiethrows |
3. Złap wszystkie wyjątki
Jeśli metoda nie rzuca wyjątków do metody wywołującej, metoda wywołująca zawsze będzie miała pewność, że wszystko poszło dobrze. I nie będzie w stanie podjąć żadnych działań, aby poprawić sytuację.
Kod | Notatka |
---|---|
|
Ta metoda wyłapuje wszystkie błędy. Metoda wywołująca upewni się, że wszystko poszło dobrze. |
3. Wielokrotne przechwytywanie wyjątków
Programiści naprawdę nie lubią powielać kodu. Wymyślili nawet taką zasadę rozwoju - DRY : Don't Repeat Yourself. Jednak podczas obsługi wyjątków często pojawiają się sytuacje, w których po bloku następuje try
kilka bloków catch
z tym samym kodem.
A może np. 3 catch
bloki z jednym kodem i jeszcze 2 catch
bloki z innym. Ogólnie rzecz biorąc, standardową sytuacją jest odpowiedzialne podejście do obsługi wyjątków w projekcie.
Począwszy od wersji 7, język Java dodał możliwość określenia kilku typów wyjątków w jednym bloku catch
. Wygląda to mniej więcej tak:
try
{
// Code where an exception might occur
}
catch (ExceptionType1 | ExceptionType2 | ExceptionType3 name)
{
// Exception handling code
}
Bloków catch
może być dowolna liczba . catch
Nie można jednak określić wyjątków, które są dziedziczone po sobie w tym samym bloku . Te. nie możesz napisać catch ( Exception
| RuntimeException
e), ponieważ klasa RuntimeException
jest dziedziczona z Exception
.
GO TO FULL VERSION