Znowu artykuł i znowu Java. 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.

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.

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 za to chociaż spróbować taki "ładniej ubrać w słowa", osadzić w okienko komunikatu i jakoś podpowiedzieć użytkownikowi co KONKRETNIE doprowadziło do awarii programu i 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
{
	riskyMethod();
}
catch (Exception e)
{
	//instrukcje wykonywane w momencie przechwycenia wyjątku
}

Metoda "riskyMethod" może posiadać w naszym przykładzie 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". To jest typ wyjątków mogących wystąpić w trakcie wykonywania programu. 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 za pomocą słów kluczowych "try" i "catch"

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" i więcej informacji możecie znaleźć w osobnym 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;
	
	riskyMethod();
}
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 pojawić się w funkcji "riskyMethod". Blok "try-catch" pozwala na takie rozgałęzienia, ale "try" musi zostać 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 "switch" omawianej parę dni wcześniej albo nawet w zwykłej instrukcji warunkowej posiadającej kilka bloków "else if". Też wykonuje tylko jeden z nich, prawda?

"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
{
	riskyMethod();
}
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 "ciągu" bloków "catch" i jak wspomniałem, wykonuje się po przeprowadzeniu wszystkich operacji w "try" (gdy obyło się bez przeszkód) oraz określonego bloku "catch" (gdy funkcja napotkała problem i zgłasza go funkcji wywołującej), 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!

PODOBNE ARTYKUŁY