1. Rodzaje wyjątków

Rodzaje wyjątków w Javie

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 Throwablezawiera 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 Throwablejest 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, catchktó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

RuntimeExceptionsjest rodzajem (podzbiorem) wyjątków Exceptions. Można nawet powiedzieć, że RuntimeExceptionjest 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 Exceptiono różnicyRuntimeException


2. Sprawdzone wyjątki: Throws, sprawdzone wyjątki

Sprawdzone wyjątki: zgłoszenia, sprawdzone wyjątki

Wszystkie wyjątki w Javie są podzielone na 2 kategorie - zaznaczone ( zaznaczone ) i niezaznaczone ( niezaznaczone ).

Wszystkie wyjątki odziedziczone po klasach RuntimeExceptioni Errorsą uważane za niesprawdzone wyjątki , wszystkie inne są uważane za sprawdzone wyjątki .

Ważny!

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
public void calculate(int n) throws Exception
{
   if (n == 0)
      throw new Exception("n is null!");
}
public void calculate(n)
{
   if (n == 0)
      throw new RuntimeException("n is null!");
}

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 throwsi 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, throwsoddzielone 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 catchdla 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
public void createWorld(int n) throws EmptyWorldException, LonelyWorldException
{
   if (n == 0)
      throw new EmptyWorldException("There are no people!");
   if (n == 1)
      throw new LonelyWorldException ("There aren't enough people!");
   System.out.println("A wonderful world was created. Population: " + n);
}
Metoda potencjalnie zgłasza dwa sprawdzone wyjątki :

  • Pusty świat
  • Samotny świat

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
public void createPopulatedWorld(int population)
throws EmptyWorldException, LonelyWorldException
{
   createWorld(population);
}
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
public void createNonEmptyWorld(int population)
throws EmptyWorldException
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
}
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
public void createAnyWorld(int population)
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
   catch (EmptyWorldException e)
   {
      e.printStackTrace();
   }
}
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 trykilka bloków catchz tym samym kodem.

A może np. 3 catchbloki z jednym kodem i jeszcze 2 catchbloki 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 catchmoże być dowolna liczba . catchNie 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| RuntimeExceptione), ponieważ klasa RuntimeExceptionjest dziedziczona z Exception.