Literatur

Exception Handling

In diesem Kapitel widmen wir uns der Fehlerbehandlung. Fehler führen in anderen Programmiersprachen, wie z.B.. in C, direkt zu Programmabstürzen. Diese Fehler werden in Java als Exception (Ausnahme) bezeichnet. Eine Exception ist ein schwerwiegender Fehler, der ohne Behandlung zu Abstürzen oder unerwünschten Programmzuständen führt. Exceptions treten immer erst zur Laufzeit ein, d. h. erst bei der Ausführung. Dies passiert unter anderem bei Arithmetischen Operationen (Division durch 0), Verletzung von Arraygrenzen, Typkonvertierung oder bei Zugriff auf noch nicht erzeugte Objekte.

Programme können trotz Auftreten dieser Fehler normal ausgeführt werden, wenn sie richtig behandelt werden. Zur Behandlung dieser Fehler wird ein sogenannter try-catch-Block verwendet. In dem try-Block werden alle Anweisungen implementiert, bei denen ein Fehler auftreten kann. Im catch-Block stehen die Anweisungen, die ausgeführt werden sollen, wenn bestimmte Fehler eintreten. Diese können z.. B. darin bestehen, den Fehler zu ignorieren oder eine Fehlermeldung auszugeben.

Eine weitere Möglichkeit einen Fehler zu behandeln, ist, diesen an den Aufrufer weiter zu reichen, da möglicherweise an dieser Stelle keine ausreichende Möglichkeit besteht, den Fehler gut zu behandeln.

Ziel des Exception-Handlings ist es außerdem, die Übersichtlichkeit zu verbessern, indem man einfachen Quellcode von möglicherweise fehlerverursachendem Quellcode trennt.

Ein geübter Softwareentwickler kann aus einer Exception viele Informationen gewinnen, die ihm bei der Fehlerbeseitigung helfen. Eine Exception liefert in der Regel die genaue Zeilennummer und die Klasse, in der der Fehler aufgetreten ist. Da es auch unterschiedliche Arten von Exceptions gibt, kann ein Entwickler auch oft schon an der Art vermuten, warum es zu dem Fehler kam. Somit dient ein gutes Exception-Handling auch dazu, die Fehlerursache zu analysieren und zu beseitigen.

Um zu sehen, was bei einer Exception im unbehandelten Fall passiert, schauen Sie sich das folgende Beispiel an:

public class Main
{
    public static void main(String[] args)
    {
        Punkt pTest=null;
        // In der nächsten Zeile wird eine Exception geworfen.
        int rueckgabe = pTest.getX_koordinate();
    }
}

Dadurch, dass wir unser Punkt-Objekt mit null initialisieren, können wir natürlich weder auf die Attribute noch auf die Methoden zugreifen. Deswegen wird bei dem Zugriff auf die Methode getX_koordinate eine Exception geworfen. Diese sieht wie folgt aus.

Exception in thread "main" java.lang.NullPointerException
        at beispieltest.Main.main(Main.java:20)

Diese Exception verrät uns als Programmierer schon sehr viel. In der ersten Zeile steht der Fehlertyp. In diesem Fall ist es die sogenannte NullPointerException. Diese tritt immer auf, wenn auf ein nicht initialisiertes Objekt bzw. nicht erzeugtes Objekt zugegriffen wird. Die nächsten Zeilen (in diesem Fall ist es nur eine) verraten uns, in welchem Paket, Klasse, Methode und Zeilennummer der Fehler aufgetreten ist. Diese Zeilen nennt man auch Aufruferliste oder CallStack. Hier kann man dann verfolgen, welche Methoden in welchen Klassen vorher ausgeführt wurden bis dieser Fehler aufgetreten ist. In unserem Falle trat der Fehler in dem Paket beispieltest auf. Die Klasse, in der der Fehler aufgetreten ist, war die Klasse Main. Die verursachende Methode war die main-Methode in der Klasse beispieltest.Main.main (von links nach rechts: Pakete, Klasse, Methode). In Klammern dahinter wird uns die Datei angegeben und die Fehlerzeile.

Damit es jedoch nicht zu solch einem Absturz mit einer für den Anwender in der Regel unverständlichen Fehlermeldung kommt, sollten mögliche Fehler abgefangen werden.

Das folgende Bild soll Ihnen das Exception-Handling verdeutlichen.

 

try,catch.exception

 

Die linke Seite des Bildes symbolisiert einen Programmabsturz, da keine Fehlerbehandlung durchgeführt wurde. Die rechte Seite hingegen fängt die Exceptions im catch-Block sicher auf und verhindert so einen Programmabsturz.

Schauen wir uns nun mal den Aufbau von try-catch-Blöcken an.

try
{
    // Hier können Exceptions auftreten
}
catch( Exception e)
{
    // Hier werden sie abgearbeitet
    // Catch ist optional, sofern ein finally-Block folgt
    // Es können mehrere catch-Blöcke hintereinander stehen, um    
    // unterschiedliche Exceptions abzufangen
}
finally
{
    // Wird immer durchlaufen, ist allerdings optional
}

Die Ausnahmebehandlung beginnt immer erst mit dem sogenannten try-Block, nach dem Motto "Probier mal, ob's funktioniert!". In dem try-Block stehen Anweisungen, deren Ausführung versucht werden soll. Sollte dort bei einer Anweisung eine Exception geworfen werden, so wird diese in den catch-Block übergeben. In der Zeile, wo die Exception geworfen wird, wird direkt der try-Block verlassen, d.h.. danach folgende Anweisungen innerhalb des try-Blockes werden nicht mehr ausgeführt.

Der catch-Block ist vergleichbar mit einer Methode, der im Falle eines Fehlers eine Exception übergeben wird. In dem obigen Beispiel wird jede Exception aufgefangen, da als Datentyp des Übergabeparameters Exception steht. Exception ist die Superklasse aller Exceptions. In dem catch-Block werden in der Regel Methoden zur Fehlerausgabe ausgeführt, die dem Benutzer dann angezeigt werden. Da der User kein Java-Experte sein muss, sollte an der Stelle eine verständliche Fehlermeldung ausgegeben werden, mit der er was anfangen kann und die ihm nach Möglichkeit einen Hinweis auf die Fehlerquelle liefert.

Es können beliebig viele catch-Blöcke hinter dem try-Block vorhanden sein, wenn Sie jeweils eine andere Exception behandeln. Man könnte auch sagen, dass sich mehrere catch-Blöcke überladen.

Als letztes folgt der finally-Block. Dieser ist optional und wird immer ausgeführt, wenn er vorhanden ist.