Hierarchia klas wyjątków
Część sekcji Programowanie obiektowe ścieżki Java w Coddy. Lekcja 59 z 87.
System obsługi wyjątków w Javie opiera się na dobrze zorganizowanej hierarchii klas, której korzeniem jest klasa Throwable. Zrozumienie tej hierarchii pomaga skuteczniej przechwytywać i obsługiwać wyjątki.
Na szczycie znajduje się Throwable, klasa nadrzędna wszystkich wyjątków i błędów. Ma dwie bezpośrednie klasy podrzędne:
Throwable
├── Error // Poważne problemy (nie przechwytuj ich)
└── Exception // Problemy, z których można wyjść
└── RuntimeException // Wyjątki niekontrolowaneBłąd oznacza poważne problemy, których aplikacje nie powinny próbować obsługiwać, takie jak OutOfMemoryError lub StackOverflowError. Wskazują one na fundamentalne problemy z samą maszyną JVM.
Wyjątek to gałąź, z którą będziesz pracować najczęściej. Dzieli się na dwie kategorie: wyjątki sprawdzane (bezpośrednie podklasy Exception) i wyjątki niesprawdzane (podklasy RuntimeException).
// Typowe klasy wyjątków
Exception
├── IOException // Problemy z plikami lub siecią
├── SQLException // Problemy z bazą danych
└── RuntimeException
├── NullPointerException
├── ArrayIndexOutOfBoundsException
└── IllegalArgumentExceptionPonieważ wyjątki są klasami, podlegają zasadom dziedziczenia. Gdy przechwytujesz wyjątek typu nadrzędnego, przechwytujesz również wszystkie jego typy potomne:
try {
// jakiś kod
} catch (Exception e) {
// Przechwytuje WSZYSTKIE wyjątki (zwykle zbyt szeroki zakres)
}try {
// jakiś kod
} catch (RuntimeException e) {
// Przechwytuje tylko wyjątki czasu wykonania i ich podklasy
}Ta hierarchia pozwala obsługiwać błędy tak szczegółowo lub ogólnie, jak tego potrzebujesz, i stanowi podstawę do tworzenia własnych niestandardowych wyjątków.
Wyzwanie
ŁatwyZbudujmy analizator wyjątków, który pokaże, jak w praktyce działa hierarchia wyjątków w Javie! Utworzysz system, który przechwytuje wyjątki na różnych poziomach szczegółowości i informuje, jaki typ został przechwycony.
Rozmieścisz swój kod w trzech plikach:
ExceptionThrower.java: Utwórz klasę, która może wywoływać różne typy wyjątków na podstawie danych wejściowych. Twoja klasa powinna mieć trzy metody statyczne:triggerRuntime(String type)- W zależności od ciągu określającego typ rzuć różne wyjątki środowiska uruchomieniowego:- Jeśli typ to
"null", rzućNullPointerExceptionz komunikatem"Null value encountered" - Jeśli typ to
"index", rzućArrayIndexOutOfBoundsExceptionz komunikatem"Invalid index" - Jeśli typ to
"argument", rzućIllegalArgumentExceptionz komunikatem"Bad argument"
triggerArithmetic()- RzućArithmeticExceptionz komunikatem"Division error"triggerGeneric()- RzućIllegalStateExceptionz komunikatem"Generic runtime error"(jego hierarchia to Exception > RuntimeException > IllegalStateException)- Jeśli typ to
ExceptionAnalyzer.java: Utwórz klasę, która przechwytuje wyjątki na różnych poziomach hierarchii i określa, co zostało przechwycone. Uwzględnij następujące metody statyczne:analyzeSpecific(String type)- WywołajExceptionThrower.triggerRuntime(type)wewnątrz bloku try. Użyj oddzielnych bloków catch dlaNullPointerException,ArrayIndexOutOfBoundsExceptioniIllegalArgumentException. Dla każdego z nich wypisz:Caught specific: [exception class simple name], a następnieMessage: [exception message]analyzeWithParent()- WywołajExceptionThrower.triggerArithmetic()wewnątrz bloku try. Przechwyć wyjątek za pomocąRuntimeException(typu nadrzędnego). Wypisz:Caught via parent: RuntimeException, a następnieActual type: [exception class simple name]analyzeWithGrandparent()- WywołajExceptionThrower.triggerGeneric()wewnątrz bloku try. Przechwyć wyjątek za pomocąException(znajdującego się jeszcze wyżej w hierarchii). Wypisz:Caught via grandparent: Exception, a następnieActual type: [exception class simple name]Main.java: Połącz wszystkie elementy analizatora wyjątków! Otrzymasz jedno wejście: ciąg określający typ wyjątku (albo"null","index", albo"argument").Najpierw wypisz
=== Specific Catch ===i wywołajanalyzeSpecific, przekazując mu dane wejściowe.Następnie wypisz pustą linię,
=== Parent Catch ===i wywołajanalyzeWithParent.Na koniec wypisz pustą linię,
=== Grandparent Catch ===i wywołajanalyzeWithGrandparent.
Otrzymasz jedno wejście: typ wyjątku do wywołania ("null", "index" albo "argument").
Użyj e.getClass().getSimpleName(), aby uzyskać nazwę klasy wyjątku, oraz e.getMessage(), aby pobrać jego komunikat. To wyzwanie pokazuje, że przechwycenie wyjątku typu nadrzędnego obejmuje również wszystkie jego typy potomne: to kluczowe zagadnienie przy decydowaniu, jak szczegółowa powinna być obsługa wyjątków!
Spróbuj swoich sił
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String type = scanner.nextLine();
// TODO: Wypisz "=== Specific Catch ===" i wywołaj ExceptionAnalyzer.analyzeSpecific(type)
// TODO: Wypisz pusty wiersz, następnie "=== Parent Catch ===", a potem wywołaj ExceptionAnalyzer.analyzeWithParent()
// TODO: Wypisz pusty wiersz, następnie "=== Grandparent Catch ===", a potem wywołaj ExceptionAnalyzer.analyzeWithGrandparent()
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektySłowo kluczowe thisMetodyPola (atrybuty)Metoda konstruktoraPrzeciążanie konstruktoraPodsumowanie — prosty kalkulator4Dziedziczenie
Podstawy dziedziczenia (extends)Słowo kluczowe superPrzesłanianie metod (@Override)Łańcuch wywołań konstruktorówKlasa ObjectDziedziczenie jedno- i wielopoziomoweDlaczego Java nie obsługuje wielodziedziczenia klasPodsumowanie – hierarchia pracowników7Metody specjalne i klasa Object
Metoda toString()equals() i hashCode()Metoda clone()compareTo() i ComparableInterfejs ComparatorPodsumowanie — własne sortowanie10Obsługa wyjątków w programowaniu obiektowym
Hierarchia klas wyjątkówWłasne wyjątkiBłędy sprawdzane a niesprawdzaneWzorzec try-with-resourcesPodsumowanie – zweryfikowany użytkownik2Modyfikatory dostępu i enkapsulacja
Przegląd poziomów dostępuMetody pobierające i ustawiająceUkrywanie informacjiSłowo kluczowe finalPodsumowanie — menedżer kont bankowych5Polimorfizm
Podstawy przeciążania metodPrzesłanianie metod (w czasie wykonywania)Rzutowanie w górę i w dółOperator instanceofKlasy i metody abstrakcyjnePowtórka — kalkulator figur8Zaawansowane koncepcje OOP
Kompozycja a dziedziczenieAgregacja a kompozycjaKlasy wewnętrzne, zagnieżdżone i anonimoweEnumy i metody enumówRekordy (Java 16+)Klasy zapieczętowane (Java 17+)11Wzorce projektowe — część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec BuilderWzorzec ObserverWzorzec Strategy3Właściwości klas i składowe statyczne
Zmienne instancji a zmienne statyczneMetody statyczneBloki statyczneStałe (static final)Powtórka – Counter i Utility6Interfejsy i klasy abstrakcyjne
Wprowadzenie do interfejsówImplementowanie interfejsówImplementacja wielu interfejsówMetody domyślne i statyczne w interfejsieKlasy abstrakcyjne a interfejsyInterfejsy funkcyjnePodsumowanie — system płatnościPoćwicz samodzielnie: Kompilator Java online