Dzisiejszym tematem jest przechwytywanie wyjątków w języku Java, dowiemy się co to takiego, jak działa i jak się zabezpieczyć przed niepożądanym działaniem w trakcie korzystania z "ryzykownej" metody za pomocą słów kluczowych "try", "catch" i "finally". Jeśli nałogowo korzystacie z języka Java, opanujcie to jak najprędzej, to jest jeden z tematów podstawowych :O.
Tweet |
CZYM JEST WYJĄTEK I JAK ON DZIAŁA?
"Wyjątek" jest mechanizmem zmieniającym przebieg działania programu polegającym na wysyłaniu sygnału do systemu gdy nastąpi sytuacja nieoczekiwana, a także niepożądana. Dam przykład. Brakuje pliku tekstowego w podanym katalogu. Wyjątkiem będzie nieznalezienie wymaganego pliku o podanej ścieżce dostępu. Może to być również próba dzielenia przez zero i wtedy wyjątek jest oczywisty - sprzeczna równość niemająca sensu matematycznego. Jeśli dopiero zaznajamiacie się z wyjątkami, dobrze jest na sam początek wymyślić samemu jakieś sytuacje, w których może on wystąpić. Takie proste rzeczy z życia wzięte - wtedy będzie łatwiej to zrozumieć.
Wyjątek sam w sobie, oprócz tego co napisałem przed chwilą, jest w rzeczywistości obiektem! Instancją typu "Exception", choć tak naprawdę to przeważnie typem jakiejś jego klasy potomnej. "Exception" to klasa bazowa wszystkich wyjątków i jak można się domyślić, powstało wiele klas potomnych celem posortowania wszystkich rodzajów wyjątków zgodnie z zaistniałą sytuacją. Na przykład "FileNotFoundException" będzie oznaczać zgłoszenie wyjątku nieznalezienia pliku o podanej nazwie. A z kolei "NullPointerException" - próbę skorzystania z danej składowej lub wywołania metody z obiektu, który nie powstał (jest wartością "null").
Zanim przejdę do pokazywania na czym polega przechwytywanie wyjątków w języku Java, chcę napisać jeszcze o jednej istotnej rzeczy. Wyjątek w przeciwieństwie do błędu, może zostać "przechwycony" przez metodę i w ten sposób możliwe jest wykonanie pewnych instrukcji, która ten wyjątek "obsłuży" i zapobiegnie wysypaniu się programu. Wiadomym jest, że w większości przypadków nie da się "naprawić wyjątku", ale można chociaż spróbować ładniej ubrać w słowa, osadzić w okienko komunikatu i jakoś podpowiedzieć użytkownikowi co KONKRETNIE doprowadziło do awarii programu, a także jak można temu zaradzić, jeśli można.
PRZECHWYTYWANIE WYJĄTKÓW W JĘZYKU JAVA JAKO PRZYKŁAD KODU ŹRÓDŁOWEGO
Pora na wyjaśnienie od strony kodowej! Pokażę Wam jak korzystać z obsługi wyjątków w kodzie źródłowym. Podstawowa struktura przechwytywania wyjątków zazwyczaj składa się co najmniej z dwóch części (może być również trzecia, "finally" którą znajdziecie na samym dole):
try {
// instrukcje mogące się nie powieść
} catch (Exception e) {
// instrukcje wykonywane w momencie przechwycenia wyjątku
}
Blok "try" może posiadać instrukcje, które mogą się "zderzyć" z nieoczekiwaną sytuacją. Gdy takowa wystąpi, metoda "zgłasza" wyjątek i przekazuje go metodzie korzystającej z tej samej metody, która ten sygnał przesłała. Traktujcie konstrukcję "try-catch" jak punkt obsługi sygnału wysłanego przez wyjątek. Miejcie również na uwadze to, że Java bardzo uważnie "pilnuje" obsługiwania potencjalnych wyjątków. Jeżeli metoda może zgłosić jakiś sygnał, każde wywołanie MUSI się znaleźć wewnątrz instrukcji "try-catch", bo inaczej pożegnamy się z kompilacją programu!!! Jedynym "wyjątkiem" od tego rygoru są wyjątki typu "RuntimeException". One nie muszą być obsługiwane, gdyż zdecydowana większość przypadków awarii podczas działania dotyczy niewłaściwego zaprogramowania przez nas, a nie potencjalnych zagrożeń wynikających z niemożności wykonania instrukcji.
Przechwytywanie wyjątków w języku Java jest możliwe po zastosowaniu konstrukcji "try-catch". KAŻDE wywołanie metody ryzykownej musi znaleźć się wewnątrz bloku "try"!
Możemy również sprawić, aby metoda korzystająca z innej ryzykownej metody, nie obsługiwała wyjątku tylko również go przekazała dalej, aby metoda wywołująca posiadała blok "try-catch". Tutaj przyda się znajomość słowa kluczowego "throws" (więcej informacji w załączonym artykule).
PRZECHWYTYWANIE WYJĄTKÓW W JĘZYKU JAVA ROZŁOŻONE NA KILKA PRZYPADKÓW
Jak już napisałem, wyjątki także są obiektami języka Java! Cenny wniosek nasuwa się taki, że one również mają swoje dziedziczenia. Samo "Exception" to klasa główna, a na przykład "ArithmeticException" dziedziczy od klasy bazowej. To z kolei oznacza, że przechwytywanie wyjątków w języku Java może dotyczyć wielu sytuacji w jednym bloku "try-catch". Pozwólcie, że zaprezentuję:
try {
int n = 12 / 0;
} catch (ArithmeticException ae) {
System.out.println("Nie dzieli się przez zero!");
ae.printStackTrace();
} catch (Exception e) {
System.out.println("Pojawił się inny błąd niż dzielenie przez zero.");
e.printStackTrace();
}
Patrząc na ten fragment możecie dostrzec dwa kolejne istotne spostrzeżenia. Po pierwsze, można bez przeszkód podstawiać wiele bloków "catch", które mają na celu zapobiec każdemu przypadkowi wszystkich "ryzykownych" metod i instrukcji. Dlatego też należy dać osobny blok dla sytuacji dzielenia przez zero oraz dla innej dowolnej sytuacji, która może wystąpić. Blok "try-catch" pozwala na takie rozgałęzienia, ale "try" może być tylko jedno!
Po drugie, bloki "catch" są sprawdzane po kolei idąc z góry na dół. To jest bardzo ważne, aby zaczynać od uwzględniania najbardziej szczególnych przypadków, a kończyć na klasie bazowej "Exception". Gdy wystąpi wyjątek i on "znajdzie" odpowiedni typ, przechodzi do niego, wykonuje instrukcje i KOŃCZY swoje działanie. To działa identycznie jak w instrukcji wielokrotnego wyboru "switch" oraz w instrukcji warunkowej posiadającej kilka bloków "else if".
"FINALLY" W BLOKU "TRY-CATCH"
Blok o powyższej nazwie jest całkowicie opcjonalny i zwykle rzadko jest potrzebny. Całość z "doczepionym" blokiem wygląda tak:
try {
// instrukcje mogące się nie powieść
} catch (Exception e) {
// instrukcje wykonywane w momencie przechwycenia wyjątku
} finally {
System.out.println("Koniec ryzykownej operacji.");
}
Ta część klauzuli umieszczana jest zawsze na końcu wszystkich bloków "catch" i jak wspomniałem, wykonuje się zarówno po przeprowadzeniu wszystkich operacji w "try", gdy obyło się bez przeszkód, jak i określonego bloku "catch", gdy metoda napotkała problem i zgłasza wyjątek. Krótko pisząc, wykonuje się niezależnie od rezultatu.
W taki oto sposób załatwiliśmy następny temat dotyczący ochrony programu. Przechwytywanie wyjątków w języku Java musi być przez Was doskonale opanowane. To jest podstawa!