Znowu artykuł i znowu Java. Przejdziemy do przechwytywania wyjątków, 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ą klauzuli "try-catch". Jeśli nałogowo korzystacie z języka Java, opanujcie to jak najprędzej, to jest jeden z tematów podstawowych.

TEORIA WYJĄTKU I KLAUZULA TRY-CATCH

"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 się zaznajamiacie się z wyjątkami, dobrze jest na sam początek wymyślić samemu jakieś sytuacje w których może wystąpić wyjątek. Takie proste rzeczy z życia wzięte.

Zanim przejdę do omawiania klauzuli "try-catch" 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". Można za to spróbować taki wyjątek "ładniej ubrać w słowa", osadzić w okienko komunikatu i jakoś podpowiedzieć użytkownikowi co KONKRETNIE może zrobić w tej sytuacji.

Pora na wyjaśnienie od strony "kodowej"! Pokażę Wam jak korzystać z przechwytywania wyjątków w kodzie źródłowym. Podstawowa struktura klauzuli "try-catch" zawsze składa się co najmniej z dwóch części (może być również trzecia "finally"):

try
{
	ryzykownaMetoda();
}
catch (Exception e)
{
	//instrukcje wykonywane w momencie przechwycenia wyjątku
}

Metoda "ryzykownaMetoda" 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 "try-catch" jak punkt obsługi sygnału wysłanego przez wyjątek.

Try-catch

Przechwytywanie wyjątków jest możliwe po zastosowaniu klauzuli "try-catch".

PRZEKAZYWANIE SYGNAŁU DO POPRZEDNICH FUNKCJI

Możemy również sprawić, aby funkcja, która korzysta z ryzykownej metody nie obsługiwała wyjątku tylko również go przekazała dalej, aby poprzednia metoda posiadała "try-catch". Tutaj przyda się znajomość wyrażeń ze słowem "throws". Po zakończeniu podawania argumentów formalnych w nagłówku funkcji, po zamknięciu nawiasu piszemy coś takiego:

void metoda() throws Exception
{
	// instrukcje
	
	ryzykownaMetoda();
	
	// instrukcje
}

Ten zapis pozwala na pominięcie obsługi sygnału na tym "etapie" i przekazanie tej czynności poprzedniej funkcji, która ją wywołała. Dzięki temu, można zapisać klauzulę "try-catch" w poprzedniej metodzie.

WIELE GAŁĘZI PRZECHWYTYWANIA

Jak wiecie (albo i nie), 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 możemy obsłużyć wiele sytuacji w jednej klauzuli "try-catch". Pozwólcie, że zaprezentuję:

try
{
	int n = 12 / 0;
	
	ryzykownaMetoda();
}
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 "ryzykownaMetoda". "try-catch" pozwala na takie rozgałęzienia.

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. To działa identycznie jak w instrukcji "switchomawianej 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?


W taki oto sposób załatwiliśmy następny temat dotyczący ochrony programu. Wspomniałem jeszcze o trzeciej części klauzuli "try-catch", "finally". Na nią poświęcę kolejny artykuł, który pojawi się za parę godzin. Jest powód aby to zrobić.