Wyjątki 180 / 196
Wyjątki W Javie istnieje mechanizm tzw. wyjątków (ang. exception), który pozwala na przechwytywanie błędów pojawiających się w programie. Kompilacja tab [ 1 0 ] = 100; spowoduje powstanie wyjątku związanego z przekroczeniem dopuszczalnego zakresu tablicy: E x c e p t i o n i n t h r e a d " main " j a v a. l a n g. A r r a y I n d e x O u t O f B o u n d s E x c e p t i o n : 10 a t Main. main ( Main. j a v a : 4 ) 181 / 196
Gdyby możliwości wyjątków kończyły się na wyświetlaniu informacji na ekranie i przerywaniu działania programu, ich przydatność byłaby mocno ograniczona. Wygenerowany wyjątek można jednak przechwycić i wykonać własny kod obsługi błędu. Służy do tego blok instrukcji try...catch. Schemat bloku try...catch instrukcje mogące spowodować wyjątek catch (TypWyjątku identyfikatorwyjątku) { obsługa wyjątku Na stronie https://docs.oracle.com/javase/8/docs/api/index.html w pakiecie java.lang. w Exception Summary zebrano różne rodzaje wyjątków, np: ArithmeticException InstantiationException ArrayIndexOutOfBoundsException NegativeArraySizeException ClassCastException NoSuchFieldException ClassNotFoundException NoSuchMethodException IllegalAccessException NullPointerException 182 / 196
tab [ 1 0 ] = 100; System. o u t. p r i n t l n ( " N i e p r a w i d ł owy i n d e k s t a b l i c y! " ) ; Blok try...catch nie musi jednak obejmować tylko jednej instrukcji ani też tylko instrukcji mogących wygenerować wyjątek: System. o u t. p r i n t l n ( " D z i e s i ą t y e l e m e n t t a b l i c y : " + t a b [ 1 0 ] ) ; System. o u t. p r i n t l n ( " N i e p r a w i d ł owy i n d e k s t a b l i c y! " ) ; 183 / 196
Nie trzeba również obejmować blokiem try instrukcji bezpośrednio generujących wyjątek. Wyjątek wygenerowany przez obiekt klasy Y może być przechwytywany w klasie X, która korzysta z obiektów klasy Y. public class Tablica { p r i v a t e i n t [ ] t a b l i c a = new i n t [ 1 0 ] ; public int pobierzelement ( int indeks ) { return tablica [ indeks ] ; p u b l i c void ustawelement ( i n t indeks, i n t wartosc ) { t a b l i c a [ indeks ] = wartosc ; T a b l i c a t a b l i c a = new T a b l i c a ( ) ; t a b l i c a. ustawelement (5, 1 0 ) ; int l i c z b a = t a b l i c a. pobierzelement (10); System. o u t. p r i n t l n ( l i c z b a ) ; System. o u t. p r i n t l n ( " N i e p r a w i d ł owy i n d e k s t a b l i c y! " ) ; 184 / 196
public c l a s s Wyjatki { public void f () { g(); System. o u t. p r i n t l n ( " Wyją t e k : metoda f " ) ; public void g () { h(); System. o u t. p r i n t l n ( " Wyją t e k : metoda g " ) ; public void h () { i n t [ ] t a b = new i n t [ 0 ] ; tab [ 0 ] = 1; System. o u t. p r i n t l n ( " Wyją t e k : metoda h " ) ; W y j a t k i e x = new W y j a t k i ( ) ; ex. f ( ) ; System. o u t. p r i n t l n ( " Wyją t e k : metoda main " ) ; Które bloki try zostaną wykonane? Zasada: zostanie wykonany blok znajdujący się najbliżej instrukcji powodującej wystąpienie wyjątku. Zatem będzie to jedynie blok obejmujący wywołanie instrukcji tab[0] = 1; w metodzie h. 185 / 196
Wyjątek jest obiektem Schemat bloku try...catch instrukcje mogące spowodować wyjątek catch (TypWyjątku identyfikatorwyjątku) { obsługa wyjątku Wyjątek to obiekt powstający, kiedy w programie wystąpi sytuacja wyjątkowa. Typ wyjątku to klasa opisująca ten obiekt. Identyfikator wyjątku to zmienna obiektowa (referencyjna) wskazująca na obiekt wyjątku. 186 / 196
Wyjątek jest obiektem System. o u t. p r i n t l n ( " N i e p r a w i d ł owy i n d e k s t a b l i c y! " ) ; System. o u t. p r i n t l n ( " Komunikat systemowy : " ) ; System. o u t. p r i n t l n ( e ) ; N i e p r a w i d ł owy i n d e k s t a b l i c y! Komunikat systemowy : j a v a. l a n g. A r r a y I n d e x O u t O f B o u n d s E x c e p t i o n : 10 187 / 196
Hierarchia wyjątków Każdy wyjątek jest obiektem pewnej klasy, które podlegają regułom dziedziczenia, np. dla wyjątku ArrayIndexOutOfBoundsException: Object -> Throwable -> Exception -> RuntimeException -> ArrayIndexOutOfBoundsException Jeśli instrukcja może wygenerować wyjątek typu X, możemy przechwycić wyjątek ogólniejszy, czyli taki, którego typem będzie jedna z klas nadrzędnych do X. c a t c h ( RuntimeException e ) { System. o u t. p r i n t l n ( " N i e p r a w i d ł owy i n d e k s t a b l i c y! " ) ; System. o u t. p r i n t l n ( " Komunikat systemowy : " ) ; System. o u t. p r i n t l n ( e ) ; Można również przechwycić wyjątek jeszcze bardziej ogólny: c a t c h ( Exception e) Jeśli instrukcje, które są obejmowane blokiem try...catch, mogą spowodować wiele różnych wyjątków, zamiast stosować wiele oddzielnych instrukcji przechwytujących konkretne typy błędów, często lepiej jest użyć jednej przechwytującej wyjątek ogólniejszy. 188 / 196
Przechwytywanie wielu wyjątków W jednym bloku try...catch można przechwytywać wiele wyjątków. Konstrukcja taka zawiera wtedy jeden blok try i wiele bloków catch. Schemat bloku try...catch instrukcje mogące spowodować wyjątek catch (KlasaWyjątku1 identyfikatorwyjątku1) { obsługa wyjątku catch (KlasaWyjątku2 identyfikatorwyjątku2) { obsługa wyjątku... catch (KlasaWyjątkuN identyfikatorwyjątkun) { obsługa wyjątku Po wygenerowaniu wyjątku następuje sprawdzenie, czy jest on klasy KlasaWyjątku1 (inaczej: czy jego typem jest KlasaWyjątku1). Jeśli tak - są wykonywane instrukcje obsługi tego wyjątku i blok try...catch jest opuszczany. Jeżeli jednak wyjątek nie jest klasy KlasaWyjątku1, następuje sprawdzenie, czy jest on klasy KlasaWyjątku2 itd. 189 / 196
Przechwytywanie wielu wyjątków Kolejność przechwytywania wyjątków nie ma znaczenia, o ile wszystkie wyjątki są na jednym poziomie hierarchii. ma znaczenie, gdy przechwytuje się wyjątki z różnych poziomów: najpierw muszą to być te bardziej szczegółowe (stojące niżej w hierarchii), potem bardziej ogólne (stojące wyżej w hierarchii). Poniższy kod zakończy się błędem catch ( RuntimeException e ) { System. o u t. p r i n t l n ( e ) ; System. o u t. p r i n t l n ( e ) ; E x c e p t i o n i n t h r e a d " main " j a v a. lang. E r r o r : Unresolved c o m p i l a t i o n problem : Unreachable catch block f o r ArrayIndexOutOfBoundsException. I t i s a l r e a d y h a n d l e d by t h e c a t c h b l o c k f o r R u n t i m e E x c e p t i o n a t Main. main ( Main. j a v a : 1 0 ) 190 / 196
catch ( RuntimeException e ) { System. o u t. p r i n t l n ( e ) ; System. o u t. p r i n t l n ( e ) ; Wyjaśnienie: Błąd bardziej ogólny zawiera już w sobie błąd bardziej szczegółowy. Jeśli przechwyci się najpierw wyjątek RuntimeException, to tak jakby przechwycić już wyjątki wszystkich klas dziedziczących po RuntimeException. Poprawiony kod: System. o u t. p r i n t l n ( e ) ; catch ( RuntimeException e ) { System. o u t. p r i n t l n ( e ) ; 191 / 196
Przechwytywanie wielu wyjątków i n t A [ ] = new i n t [ 1 0 ] ; System. o u t. p r i n t l n ( "Z ł y i n d e k s! " ) ; catch ( Exception e ){ System. o u t. p r i n t l n ( "B ł ą d og ó l n y " ) ; Zł y indeks! Pojawiło się zgłoszenie tylko pierwszego błędu. Jeśli w bloku try któraś z instrukcji spowoduje wygenerowanie wyjątku, dalsze instrukcje z tego bloku nie zostaną wykonane (blok zostaje przerwany). 192 / 196
Przechwytywanie wielu wyjątków Zmieńmy kolejność instrukcji w bloku try: i n t A [ ] = new i n t [ 1 0 ] ; System. o u t. p r i n t l n ( "Z ł y i n d e k s! " ) ; catch ( Exception e ){ System. o u t. p r i n t l n ( "B ł ą d og ó l n y " ) ; B ł ą d og ó l n y 193 / 196
Przechwytywanie wielu wyjątków W Java 7 i nowszych dostępna jest możliwość przychwycenie kilku typów wyjątków w jednym bloku catch. Poszczególne typy należy oddzielić od siebie pionową kreską. Wtedy niezależnie od tego, jaki wyjątek z wymienionych wystąpi, zostanie wykonany taki sam kod (zawarty w bloku catch). i n t A [ ] = new i n t [ 1 0 ] ; catch ( ArrayIndexOutOfBoundsException NegativeArraySizeException System. o u t. p r i n t l n ( "Z ł y i n d e k s l u b ujemny r o z m i a r t a b l i c y " ) ; catch ( Exception e ){ System. o u t. p r i n t l n ( "B ł ą d og ó l n y " ) ; e) { Z ł y i n d e k s l u b ujemny r o z m i a r t a b l i c y 194 / 196
Zagnieżdżenie bloków try...catch W jednym bloku przechwytującym wyjątek X może istnieć drugi blok, który będzie przechwytywał wyjątek Y. Schemat zagnieżdżenia instrukcje mogące spowodować wyjątek 1 instrukcje mogące spowodować wyjątek 2 catch (TypWyjątku2 identyfikatorwyjątku2) { obsługa wyjątku 2 catch (TypWyjątku1 identyfikatorwyjątku1) { obsługa wyjątku 1 195 / 196
Zagnieżdżenie bloków try...catch System. o u t. p r i n t l n ( "Z ł y i n d e k s! " ) ; i n t A [ ] = new i n t [ 1 0 ] ; catch ( Exception e ){ System. o u t. p r i n t l n ( "B ł ą d og ó l n y " ) ; Zł y indeks! B ł ą d og ó l n y 196 / 196