Wykład 8: Obsługa Wyjątków
Wyjątki Wyjątek to sytuacja nienormalna, która pojawia się w trakcie wykonania programu. W językach bez obsługi wyjątków, błędy są wykrywane i obsługiwane ręcznie, zwykle przez kody błędów. Java dostarcza specjalnych konstrukcji językowych do sygnalizacji, wykrywania i obsługi błędów.
Wyjątki w Javie Wyjątek to obiekt, który opisuje sytuację wyjątkową (błędną) powstałą w kodzie programu: Kiedy powstaje błąd, wyjątek opisujący go jest "wyrzucany" w metodzie która ten błąd spowodowała. Metoda może "wyłapać" i "obsłużyć" wyjątek samodzielnie, lub przekazać go dalej. Błąd jest na koniec wyłapany i obsługiwany.
Konstrukcje Obsługi Wyjątków try otacza część programu, którą chcemy monitorować na wypadek sygnalizacji błędów catch w parze z try, wyłapuje określone wyjątki i obsługuje je w pewien sposób throw sygnalizuje powstanie określonego wyjątku throws określenie jakie wyjątki może dana metoda sygnalizować finally kod, który musi być koniecznie wywołany przed opuszczeniem danej metody
Blok Obsługi Wyjątków Blok try/catch/finally do obsługi dwóch rodzajów wyjątków (TypWyjatku1 i TypWyjatku2): try { //monitorowana część kodu catch(typwyjatku1 e) { //obsluga wyjatku dla typu 1 catch(typwyjatku2 e) { //obsluga wyjatku dla typu 2 finally { //kod do wykonanie przed zakonczeniem
Hierarchia Wyjątków Throwable obejmuje wszystkie wyjątki Exception wyjątki do wyłapania przez programy użytkowe RuntimeException definiowane automatycznie dla programów: dzielenie przez zero indeksowanie tablic itp. TypWyjatku wyjątki użytkownika Error nie do wyłapania przez programy użytkowe, błędy środowiska wykonawczego
Domyślna Obsługa Wyjątków class Wyjatek0 { public static void main(string args[]) { int d = 0; int a = 42 / d; Gdy system wykrywa dzielenie przez zero, tworzy nowy obiekt wyjątku, i wyrzuca go. Z braku własnej procedury obsługi, wyjątek jest przechwycony przez procedurę domyślną, która wyświetla komunikat, stos wywołań i powoduje zakończenie.
Domyślna Obsługa Wyjątków Stos wywołań: ciąg wywołań metod które prowadziły do wystąpienia błędu. class Wyjatek1 { static void metoda() { int d = 0; int a = 10 / d; public static void main(string args[]) { Wyjatek1.metoda();
Własna Obsługa Wyjątków Korzyści własnej obsługi błędów: umożliwia poprawianie błędów, zapobiega zakończeniu działania programu. class Wyjatek2 { public static void main(string args[]) { int d, a; Należy umieścić kod do monitorowania w bloku try: try { d = 0; a = 42 / d; System.out.println("Nieosiągalne");
Własna Obsługa Wyjątków Należy określić które wyjątki chcemy wyłapać: catch (ArithmeticException e) { Oraz jak te wyjątki obsłużyć: System.out.println("Dzielenie przez 0"); Kod po obsłudze wyjątku: System.out.println("Po wyjatku");
Try i Catch Bloki try i catch stanowią parę. Gdy wyrzucany jest wyjątek w bloku try: try { d = 0; a = 42 / d; System.out.println("Nieosiągalne"); kontrola przechodzi natychmiast do bloku catch: catch (ArithmeticException e) {... catch nie może wyłapać wyjątków z innych bloków try, z wyłączeniem zagnieżdżonych bloków try.
Maskowanie Błędów Wyjątek jest obsługiwany, potem program kontynuuje tak jakby nic się nie wydarzyło. Generowanie liczb losowych: import java.util.random; class ObslugaBledow { public static void main(string args[]) { int a = 0, b = 0, c = 0; Random r = new Random();
Maskowanie Błędów Obsługa błędu gdy jedna z pary liczb jest zerem: for (int i=0; i<32000; i++) { try { b = r.nextint(); c = r.nextint(); a = 12345 / (b / c); catch (ArithmeticException e) { System.out.println("Dzielenie przez 0"); a = 0; System.out.println("i: " + i + "a: " + a);
Wyświetlanie Opisu Wyjątku Klasa Throwable przesłania metodę tostring() tak by wyświetlała opis wyjątku. try {... catch (ArithmeticException e) { System.out.println("Wyjatek: " + e); a = 0;
Obsługa Kilku Wyjątków Na Raz Jeden blok try i kilka catch dla różnych wyjątków. class WieleBledow { public static void main(string args[]) { try { int a = args.length; System.out.println("a= " + a); Ryzyko dzielenia przez zero: int b = 42 / a; Indeks poza zakresem tablicy: int c[] = { 1 ; c[42] = 99;
Obsługa Kilku Wyjątków Na Raz Wyłapanie i obsługa błędu dzielenia przez zero: catch(arithmeticexception e) { System.out.println("Dzielenie przez 0"); Wyłapanie i obsługa błędu indeksowania poza tablicą: catch(arrayindexoutofboundsexception e) { System.out.println("Index poza tablica"); Kod po obsłudze błędów: System.out.println("Po obsludze bledow");
Kolejność Obsługi Wyjątków W sekwencji catch, wyjątki pod-klasy muszą wystąpić przed wyjątkami nad-klasy. Pojawi się błąd kompilacji: class WyjatekPodKlasa { public static void main(string args[]) { try { int a = 0; int b = 42 / a; catch(exception e) { System.out.println("Wyjatek generyczny"); catch(arithmeticexception e) { System.out.println("Nieosiagalny");
Zagnieżdżony Blok try Jeden blok try wewnątrz innego try. class ZagniezdzonyTry { public static void main(string args[]) { Zewnętrzny blok try: try { int a = args.length; Ryzyko dzielenia przez zero: int b = 42 / a; System.out.println("a= " + a);
Zagnieżdżony Blok try Wewnętrzny blok try: try { Ryzyko dzielenia przez zero: if (a == 1) a = a /(a-a); Wykroczenie poza zakres tablicy: if (a == 2) { int c[] = {1; c[42] = 99;
Zagnieżdżony Blok try Obsługa wyjątku wykroczenia poza zakres tablicy powstałego w bloku wewnętrznym try: catch(arrayindexoutofboundsexception e){ System.out.println("Index za tablica"); Obsługa wyjątku błędu dzielenia przez zero powstałego w bloku zewnętrznym try: catch (ArithmeticException e) { System.out.println("Dzielenie przez 0);
Zagnieżdżony Blok try wyjątek powstaje w bloku wewnętrznym try i jest obsłużony przez catch w tym samym bloku wyjątek powstaje w bloku wewnętrznym try i jest obsłużony przez catch w bloku zewnętrznym wyjątek powstaje w bloku zewnętrznym try i jest obsłużony przez catch w bloku zewnętrznym brakuje instrukcji catch w obu blokach - wyjątek obsługiwany jest przez środowisko wykonawcze
Metody i Występowanie Bloków try class MetodaZagniezdzonyTry { Metoda z wewnętrznym blokiem try: static void zagniezdzonytry(int a) { try { if (a == 1) a = a /(a-a); if (a == 2) { int c[] = {1; c[42] = 99; catch (ArrayIndexOutOfBoundsException e) { System.out.println("Index poza tablica);
Metody i Występowanie Bloków try Metoda z zewnętrznym blokiem try: public static void main(string args[]) { try { int a = args.length; int b = 42 / a; System.out.println("a= " + a); zagniezdzonytry(a); catch (ArithmeticException e) { System.out.println("Dzielenie przez 0);
Wyrzucanie Wyjątków Program użytkownika może sam wyrzucać wyjątki: throw object; Obiekt musi być klasy Throwable, albo jej pod-klasy. Uzyskanie obiektu klasy Throwable: użycie operatora new użycie parametru w instrukcji catch
Obsługa throw Przerwanie wykonania na instrukcji throw: czy najbliższy otaczający blok try posiada instrukcję catch dla obsługi danego wyjątku? w przeciwnym razie, czy kolejny otaczający blok try posiada tą instrukcję? w przeciwnym razie, wykonaj domyślną obsługę wyjątku: przerwanie wykonania, drukowanie stosu
Demonstracja throw class ThrowDemo { static void metoda() { try { Tworzy nowy wyjątek i go wyrzuca: throw new NullPointerException("demo"); Wyjątek jest wyłapany natychmiast: catch(nullpointerexception e) { System.out.println("Zlapany w metodzie");
Demonstracja throw Obsługa polega na przesłaniu wyjątku dalej: throw e; Wyjątek jest złapany ponownie przez metodę main: public static void main(string args[]) { try { metoda(); catch(nullpointerexception e) { System.out.println("Zlapany ponownie");
Tworzenie Standardowych Wyjątków Tworzenie obiektu standardowej klasy wyjątku: throw new NullPointerException("demo"); Wszystkie standardowe wyjątki mają dwa konstruktory: bezparametrowy z parametrem String opisującym wyjątek; dostępny przez getmessage() w Throwable
Deklaracja throws Jeśli metoda może spowodować wyjątek którego sama nie jest w stanie obsłużyć, to musi ten fakt opisać. typ nazwa(parametry) throws wyjatki {... Niezbędne jest wymienienie wszystkich wyjątków, oprócz typów Error i RuntimeException.
Brak Deklaracji throws Metoda wyrzuca wyjątek którego ani nie wyłapuje, ani nie deklaruje. Ten program nie kompiluje się. class ThrowsDemo1 { static void metoda() { System.out.println("Wewnatrz metody"); throw new IllegalAccessException("demo"); public static void main(string args[]) { metoda();
Dodana Deklaracja throws Jedna metoda deklaruje, druga wyłapuje wyjątek: class ThrowsDemo2 { static void metoda() throws IllegalAccessException { System.out.println("Wewnatrz metody"); throw new IllegalAccessException("demo"); public static void main(string args[]) { try { metoda(); catch (IllegalAccessException e) { System.out.println("Zlapany " + e);
Deklaracja finally Kod który będzie wykonany po bloku try/catch, bez względu na powstanie wyjątków. Użyteczny gdy należy zwolnić zasoby systemowe. Każdy try musi posiadać co najmniej jedną instrukcję catch lub finally.
Demonstracja finally class FinallyDemo { static void proca() { try { System.out.println("wewnatrz proca"); throw new RuntimeException("demo"); finally { System.out.println("procA: finally"); static void procb() { try { System.out.println("wewnatrz procb"); return; finally { System.out.println("procB: finally");
Demonstracja finally static void procc() { try { System.out.println("wewnatrz procc"); finally { System.out.println("procC: finally"); public static void main(string args[]) { try { proca(); catch(exception e) { System.out.println("Wyjatek zlapany"); procb(); procc();
Standardowe Wyjątki Niesprawdzane RuntimeException są dostępne automatycznie. Nie muszą być deklarowane w sekcji throws. Kompilator nie sprawdza czy metoda deklaruje czy obsługuje te wyjątki. Inaczej wyjątki niesprawdzane.
Standardowe Wyjątki Niesprawdzane ArithmeticException błędy arytmetyczne, np. dzielenie przez zero ArrayIndexOutOfBoundsException indeks tablicy poza zakresem ArrayStoreException przypisanie tablicy nieodpowiedniego typu elementu ClassCastException niepoprawne rzutowanie IllegalArgumentException niepoprawny argument metody IllegalMonitorStateException niepoprawna operacja monitora
Standardowe Wyjątki Niesprawdzane IllegalStateException środowisko lub aplikacja jest w niepoprawnym stanie IllegalThreadStateException wymagana operacja niekompatybilna z bieżącym stanem wątka IndexOutOfBoundException jakis rodzaj indeksu jest poza zakresem NegativeArraySizeException tablica tworzona z ujemnym rozmiarem NullPointerException niepoprawne użycie wskaźnika null
Standardowe Wyjątki Niesprawdzane NumberFormatException niepoprawna konwersja stringu na format liczbowy SecurityException próba naruszenia bezpieczeństwa StringIndexOutOfBoundsException indeks poza zakresem stringu UnsupportedOperationException napotkano niepoprawną operację
Standardowe Wyjątki Sprawdzane Metody która mogą generować te wyjątki a nie potrafią ich samodzielnie obsłużyć, muszą je deklarować: ClassNotFoundException nie znaleziono klasy CloneNotSupportedException próba klonowania obiektu który nie implementuje interfejsu Cloneable. IllegalAccessException dostęp do klasy zabroniony InstantiationException próba tworzenia obiektu klasy abstrakcyjnej lub interfejsu
Standardowe Wyjątki Sprawdzane InterruptedException jeden wątek przerwany przed drugi NoSuchFieldException pole nie istnieje NoSuchMethodException metoda nie istnieje
Tworzenie Własnych Klas Wyjątków Utwórz pod-klasę Exception. Pod-klasa nie musi nic deklarować, musi tylko istnieć. Exception nie deklaruje własnych metod, ale dziedziczy po Throwable.
Demonstracja Własnych Klas Wyjątków Własna klasa wyjątków: class MojWyjatek extends Exception { private int szczegoly; MojWyjatek(int a) { szczegoly = a; Przesłonięcie metody z klasy Throwable: public String tostring() { return "MojWyjatek[" + szczegoly + "]";
Demonstracja Własnych Klas Wyjątków class MojeWyjatki { Metoda deklaruje wyjątek tej klasy: static void oblicz(int a) throws MojWyjatek { System.out.println("oblicz(" + a + ")"); Wyrzucenie wyjątku: if (a > 10) throw new MojWyjatek(a); System.out.println("Normalne wyjscie");
Demonstracja Własnych Klas Wyjątków public static void main(string args[]) { try { oblicz(1); oblicz(20); Przechwycenie wyjątku: catch (MojWyjatek e) { System.out.println("Zlapany " + e);