Kurs Java Podstawy - rozszerzony

Zgłaszanie wyjątków - instrukcja throw

W poprzedniej lekcji kursu nauczyliśmy się obsługiwać wyjątki generowane podczas wykonania programu poprzez klauzulę try catch. Dziś postaramy się dowiedzieć jak w inny sposób można je zgłaszać. Jest to umiejętność szczególnie przydatna w przypadku wyjątków, których nie da się obsłużyć, ich obsługa nie ma sensu, lub po prostu ich wystąpienie może spowodować nieprawidłową pracę w dalszych etapach programu. W większości przypadków dobrze jest w ten sposób radzić z błędami w czasie wykonania, błędami asercji, czy maszyny wirtualnej.

Schematycznie użycie instrukcji throw wygląda następująco:

 [static][final] nazwa_metody() <strong>throws</strong> typ_wyjątku1, typ_wyjątku2, ... {
             kod...
             <strong>throw</strong> new typ_wyjatku1();
             kod
...

To co istotne w powyższym przykładzie to jak widać wyjątki są obiektami - tworzymy je za pomocą instrukcji new. Równie dobrze można by najpierw utworzyć obiekt wyjątku, a dopiero później przekazać jego referencję do instrukcji throw - nie ma to jednak większego sensu.

W nagłówku metody najpierw musimy zadeklarować jakie typy wyjątków dana metoda może zgłaszać, robimy to za pomocą instrukcji throws, wymieniając po przecinku różne ich rodzaje. Później w kodzie danej metody można je zgłosić (zazwyczaj np w instrukcji if) korzystając z instrukcji throw.

Zgłaszać w ten sposób można wszystkie rodzaje wyjątków, czyli obiekty klas, które pośrednio, lub bezpośrednio dziedziczą z klasy Throwable. Hierarchię wyjątków widać poniżej:

(pożyczone z javamex.com)

Na powyższym schemacie można wyróżnić wyjątki nie wymagające obsługi (uncaught - czerwone), oraz te, które musimy zgłosić, lub obsłużyć w jeden z poznany przez nas sposobów (niebieskie).

Błędy typu Error zazwyczaj nie są generowane przez sam program, a raczej przez maszynę wirtualną, lub środowisko, jak na przykład OutOfMemoryException - zgłaszania, lub próba obsługi takich wyjątków, jak już wcześniej wspomniałem, nie ma na ogół sensu, dlatego nie jest wymagane ich zgłaszanie, czy obsługa.

Żeby wszystko podsumować spójrzmy na krótki przykład. Niech będzie to prosty program dzielący liczbę 10, przez wartość podaną przez użytkownika.

import java.util.Scanner;

public class Main {
	public static void main(String[] agrs) throws ArithmeticException{
		int x=10;
		int y;
		Scanner sc = new Scanner(System.in);
		System.out.print("Podaj dzielnik: ");
		y = sc.nextInt();
		if(y==0)
			throw new ArithmeticException("Nie mozna dzielić przez 0");
		else
			System.out.println(x/(double)y);
	}
}

Jak widać wyjątek może zgłaszać każda metoda, także main(). Najpierw deklarujemy, że może ona zgłosić wyjątek typu ArithmeticException, robimy to, gdy użytkownik wprowadzi wartość 0, bo jak wiadomo, dzielenie przez 0 nie istnieje. Jeżeli podamy prawidłową wartość (całkowitoliczbową) to wyświetli się na ekranie prawidłowy wynik.

(artykuł będzie prawdopodobnie jeszcze rozbudowany)

<- Poprzednia LekcjaNastępna Lekcja ->

Komentarze

Łukasz

Jeśli i tak stosujemy ifa do sprawdzenia wartości to możemy normalnie nim wyświetlić błąd. Rozumiem że jest to prosty przykład ale na jego podstawie za bardzo nie rozumiem sensu zgłaszania błędów.

Michał

Wcześniej zostało w tekście podane, że rzucenie nowego obiektu wyjątku powoduje przerwanie działania programu. Ale zgodzę się, że po zakończeniu bloku warunkowego powinna znaleźć się co najmniej jedna dalsza instrukcja, choćby zwykły print.

Bartek

Można by dać print a potem System.exit...
I nie wychodził by niepotrzebny komunikat błedu maszynowego.

Marcin

Nie zawsze można wyświetlić błąd. Jeżeli funkcja zwraca wynik obliczenia INT, który jest użyty gdzięś w programie, to nie można zwrócić treści błędu w postaci STRINGA, więc stosuje się wyjątek, aby obsłużyć ewentualne błędy.

bartek

ok, ale wyżej podany kod nie działa. w ogóle co to jest: throw new ArithmeticException("Nie mozna dzielić przez 0");
ten fragment kodu powinien nam coś wyświetlić?

dqbEd1

O tym, co ten fragment kodu oznacza jest ta właśnie lekcja :)

Witek

Witam
Wyświetla Ci na czerwono " Nie można dzielić przez zero"

Jantek

literówka (String[] aGRs) zamiasta args

Jack

Gdzie można znaleźć listę możliwych błędów do przechwytywania?

Sab

Jak to gdzie, Jacku - w dokumentacji Javy

Bartek

Ale kilka typów powinnien twórca tego zacnego poradnika podać!

walmen

Hej,

Panowie myślę, że przydałoby się poszerzyć temat o definiowanie własnych typów wyjątków.

GZII13

taa koniecznie by sie przydało to co walmen mówi, robie sobie przypomnienie i mi narazie tego brakuje :D, z reszta bok try catch znam to to może narazie poczekać

lokampan

Nie do końca coś chyba skumałem, jaka jest różnica kiedy zdeklarujemy że może rzucać wyjątek ArithmeticException czy IOException? Bo zamieniając ArithmeticException na IOException w podanym tutaj przykładzie efekt będzie ten sam i dostane wtedy "Exception in thread "main" java.io.IOException: Nie dziel przez zero, cholero." - a więc, po za nazwą obiektu (wyjątku) jaka tutaj jest różnica, że używa się takiego wyjątku a nie innego?

Sławek Ludwiczak

IOException jest dużo ogólniejszym typem wyjątku niż ArithmeticException. Rzucając ArithmeticException można dać dokładniejszą informację co jest problemem (dzięki temu, jeśli zrobisz gdzieś błąd, nie musisz się głowić o co chodzi, tylko masz konkretniejszą informację).
Dodatkowo przechwytując IOException możesz przechwycić dużo wyjątków za jednym zamachem (wszystkie wyjątki które dziedziczą po IOException, czyli np wyjątki, które sam sobie zdefiniujesz).
Generalnie praktycznie wszystkie wyjątki możesz obsłużyć przechwytując Exception (zgodnie z obrazkiem w lekcji) tylko tak jak pisałem - jest to niepraktyczne i dużo lepiej bardziej sprecyzować sytuacje wyjątkowe.

kowalsky

bardzo fajna strona i przydatne lekcje.
szkoda, że artykuł nie został jeszcze rozbudowany, bo wydaję mi się, że ten temat jest bardzo ważny, a podejrzewam, że również obszerny :/
pozdrawiam i życzę powodzenia w prowadzeniu kursu!

Bartek

Z tego co wiem, to Sławek zaniechał dalszego tworzenia kursu (znudziło mu sie!). :(

kęsik

Bartek, nawet tak nie strasz ;) Sławku, chwalimy Cię, to dobry kurs, wróć :D

Brodaty

Nie rozumiem wgl tych Exception, gdzie i jakie rodzaje tego dawać. Mógłby ktoś pomóc ? ;]

Marcin

To napiszcie do Sławka, by sprawdzić czy naprawdę mu się odechciało.

wiesiek

kupcie sobie książkę

scalarny

Może by tak dodać ciemne tło w kodzie programów i pogrubienie składni kolorowej, tak jakoś to tu blado wygląda i ledwo co widać kod. Mała czcionka na blogu też strasznie męczy wzrok. Na tym kursie jakoś to czytelniej wygląda, kod źródłowy http://kurs-c-plus-plus.cba.pl/?page_id=23. Albo ciemne tło i jasne wstawki z kodem, albo jasne tło i ciemne wstawki z kodem aby się rozróżniało. Nie chce się wtrącać, gdyż to nie mój blog, kurs, ale było by zdecydowanie czytelniej. Kiedy Java 8? Poza tym świetny kurs, znacie coś z JavaFX podobnie opisane?

Sławek Ludwiczak

Mnie osobiście ciemne tło bardzo męczy, ale nad czcionkami i kolorowaniem kodu popracujemy przy przenosinach na nową platformę.