Wyjątek – jest to błąd, który został wykryty w trakcie działania programu.
Podczas wystąpienia takiego błędu tworzony jest obiekt reprezentujący wyjątek, który zostaje wyrzucony metodzie, w której on wystąpił. W tej metodzie może on zostać obsłużony, lub przekazany wyżej, aż w końcu zostanie on wyłapany i obsłużony.
Na ogół wyjątki są generowane przez system wykonawczy Javy, ale istnieje także możliwość wygenerowania wyjątku przez programistę.
Jeśli nie zatroszczymy się o obsługę wyjątków, a system wykonawczy Javy go zgłosi, zostanie on dopiero przechwycony przez domyślną procedurę obsługi, która w końcowym efekcie powoduje zakończenie programu bez możliwości naprawienia błędu.
Głównym zadaniem dobrej obsługi wyjątków jest takie rozwiązanie problemu, aby dalsza część kodu nie wiedziała o jego istnieniu.

Poniżej znajduje się blok try, zawierający instrukcje, w których może pojawić się wyjątek, blok(i) catch, w których to, wyjątek zostaje wyłapany i odpowiednio obsłużony, a na samym końcu opcjonalny blok finally, z kodem, który zawsze musi się wykonać przed zakończeniem metody:

public class Main {
	public static int length;

	public static void main(String[] args) {
		try {
			String test = null;
			// odwolanie do wartosci null powoduje wyrzucenie wyjatku
			length = test.length();

			System.out.println("after Exception");

		} catch (NullPointerException eNPE) {
			System.out.println("in NullPointerException block");
			eNPE.printStackTrace();
			length = 0;
		} catch (Exception e) {
			System.out.println("in Exception block");
			e.printStackTrace();
		} finally {
			System.out.println("in finally block");
		}

		System.out.println("Variable length is " + length);
	}
}

oraz to co zostało wyświetlone na wyjściu:

in NullPointerException block
java.lang.NullPointerException
	at Main.main(Main.java:8)
in finally block
Variable length is 0

W powyższym kodzie został celowo wygenerowany błąd. W wierszu nr 6 następuje deklaracja zmiennej typu String wartością null, która to próbuje wywołać metodę length() (zwracającą długość przechowywanego obiektu String). Jednak w tym momencie zgłaszany jest wyjątek NullPointerException, który zostaje obsłużony w pierwszej klauzurze catch. Za pomocą metody printStackTrace() na wyjście wyświetlony zostaje stos wywołań, oraz przypisanie do zmiennej length wartości 0 w celu „naprawienia” kodu.
Warto zwrócić uwagę, że metoda println(„after Exception”) w ogóle nie zostanie wywołana. Także druga klauzura nie zostanie użyta.

Instrukcje w bloku finally zostaną zawsze wykonane, niezależnie czy wyjątek wystąpił, czy też nie. Dobrym przykładem użycia finally jest instrukcja zamknięcia pliku lub innych zasobów.

W przypadku użycia większej liczby catch, podczas fazy sprawdzania zostaje wybrana pierwsza, która pasuje do typu zgłaszanego wyjątku. Należy wtedy zwrócić uwagę, by na w pierwszej kolejności umieszczać klauzury wyłapujące bardziej szczegółowe wyjątki (podklasy klasy Exception – głównie RuntimeException), a na końcu dopiero klasy bazowe (Exception). Zmiana tej kolejności powoduje wystąpienie błędu na poziomie kompilacji.

exceptions-throwable

http://docs.oracle.com/javase/tutorial/essential/exceptions/throwing.html

 

W poprzednim przykładzie wyjątki zgłaszane były przez system wykonawczy Javy. Istnieje także możliwość, że programista może w dowolnym miejscu zgłosić taki wyjątek. Można to zrobić za pomocą throw. Poniższy przykład dotyczy właśnie tego zagadnienia.

public class Main {

    public static int exceptionTest(String testString) {
        int result = 0;
        try {
            // jesli wartość parametru testString wynosi null powinien zostać
            // wyrzucony wyjątek
            if (testString == null) {
                throw new NullPointerException("String is null");
            } else {
                result = testString.length();
            }
        } catch (NullPointerException e) {
            System.out.println("in NullPointerException in method");
            result = 0;
            // throw e;
        }
        return result;
    }

    public static void main(String[] args) {
        try {
            String test = null;
            exceptionTest(test);

            System.out.println("after Exception");

        } catch (NullPointerException eNPE) {
            System.out.println("in NullPointerException block");
            //eNPE.printStackTrace();
        } catch (Exception e) {
            System.out.println("in Exception block");
            //e.printStackTrace();
        } finally {
            System.out.println("in finally block");
        }
    }
}

Powyższy kod generuje na wyjściu następujące komunikaty:

in NullPointerException in method
after Exception
in finally block

oraz, gdy odkomentujemy instrukcję throw e w wierszu 16:

in NullPointerException in method
in NullPointerException block
in finally block

W metodzie exceptionTest() za pomocą instrukcji throw  w wierszu nr 9 zgłoszony jest wyjątek NullPointerException. Po instrukcji throw należy umieścić obiekt typu Throwable (lub jego podklasę). Obiekt ten można stworzyć za pomocą operatora new lub otrzymać go jako parametr w klauzurze catch.
Jeśli tworzymy obiekt wbudowanego wyjątku najczęściej posiada on 2 konstruktory: bezparametrowy lub przyjmujący ciąg znaków, który służy do nadania opisu dla tego wyjątku.
throw e w bloku catch umożliwia ponowne wyrzucenie wyjątku, który zostaje obsłużony przy następnej okazji (w zewnętrznym bloku try), lub w przypadku jego braku przez domyślną procedurę obsługi Javy (co wiąże się z zakończeniem działania programu).

Jeśli w metodzie zostanie pominięty blok sprawdzający wyjątek oraz klauzura catch nie będzie go przechwytywała należy dodać do definicji metody instrukcje throws, a po niej listę wszystkich zgłaszanych przez nią wyjątków (po przecinkach).

Następny przykład przedstawia zastosowanie instrukcji throws :

public class Main {

	public static int exceptionTest(String testString) throws Exception {
		int result = 0;

		if (testString == null) {
			throw new Exception("String is null");
		} else {
			result = testString.length();
		}
		return result;
	}

	public static void main(String[] args) {
		try {
			String test = null;
			exceptionTest(test);

			System.out.println("after Exception");

		} catch (Exception e) {
			System.out.println("in Exception block");
		} finally {
			System.out.println("in finally block");
		}
	}
}

Na wyjściu pojawią się następujące komunikaty:

in Exception block
in finally block

W razie braku deklaracji throws na etapie kompilacji pojawi się błąd „Unhandled exception type Exception”.
Wyjątki typu Error i RuntimeException (wraz z podklasami) nie muszą być deklarowane.

Warto jeszcze odwiedzić strony 4programmers.net oraz oracle.com, które krótko omawiają nowości dotyczące wyjątków w Javie 7.