Java Exceptions – Wie du Fehler abfängst und behandelst.

Keylearnings:

  • Was sind Java Exceptions?
  • Wie du mit Hilfe der try-catch Kontrollstruktur Ausnahmen abfängst.
  • Wie du mit Hilfe des Schlüsselwortes throw selber eine Exception auslöst.
  • Abschlussbehandlung mit Hilfe des Schlüsselwortes finally.
  • VIDEOERKLÄRUNG für Eclipse

Immer müssen wir mit einem DAU rechnen.

Dem dümmsten anzunehmenden User!

Außerdem passieren Dinge, die wir nicht vorhersehen können, wie z.B. der Absturz eines Servers, auf den wir zugreifen müssen.

Wie gehen wir mit solchen Ausnahmesituationen um?

Hierfür gibt es in Java das Konzept der Exceptions, das ich dir in diesem Artikel vorstellen möchte.

Was sind JAVA Exceptions

Fangen wir mit einer Fingerübung an und schreiben eine Funktion, die als Input zwei Ganzzahlen erwartet und deren Quotient zurückliefert.

1: public static int berechneDivision(int a, int b){
2:  return a/b;
3:}

Was kann hier schief gehen?

Naja, wir könnten z.B. als zweiten Parameter eine Null übergeben und wie du noch aus der Schule weißt, gehört eine Division durch Null zu den Sachen, die ganz ganz böse sind.

Also was können wir tun?

Eine naheliegende Idee ist es, diesen Fehlerfall mit Hilfe einer if Bedingung abzufangen.

1: public static double berechneDivision(int a, int b){
2:	if (b != 0){
3:	   return a/b;
4:	}else{
5:	   return 0;
6:	}
7:}

Funktioniert einwandfrei! Kann man so machen. Aber seien wir doch ruhig mal etwas experimentierfreudig und schauen was passiert, wenn wir unsere Funktion ohne diese Erweiterung aufrufen.

Also lass uns böse sein und eine Division durch Null erzeugen!

berechneDivision(3,0);

Wir versuchen drei durch Null zu dividieren. Eine mathematische Unmöglichkeit! Das weiß auch Java und rügt unser Verhalten mit folgender Fehlermeldung:

Java Exception ArithmeticException

Kim, was ist das? Ein Virus?

Keine Sorge! Genau so sieht eine Java Exception aus, welche wir sehr elegant mit Hilfe einer sogenannten try-catch Kontrollstruktur abfangen können.

Ausnahmebehandlung mit Hilfe der try-catch Kontrollstruktur

Die try-catch Kontrollstruktur handelt ganz nach dem Motto „Probieren geht über studieren“ und hat dabei keine Angst vor Fehlern.

Wir müssen nur festlegen wie unser Programm im Fehlerfall reagieren soll.

Also auf in die Praxis! Schauen wir uns das anhand unserer berechneDivision Methode an.

public static int berechneDivision(int a, int b){
1: int c = 0;
2: try{
3:	c = a/b;
4:       
5: }catch(ArithmeticException e){
6:	System.out.println("Fehler");
7: }
8: return c;
9:}

Die try-catch Struktur besteht aus zwei Teilen. In dem oberen Teil, der mit dem Schlüsselwort try (Zeile 2-5) beginnt, stehen die Anweisungen, die das Java-Programm versuchen soll auszuführen.

Tritt hierbei ein Fehler auf, wird (und nur dann) der Programmcode nach dem Schlüsselwort catch ausgeführt. In unserem Fall geben wir dann in Zeile sechs die Zeichenkette Fehler auf dem Bildschirm aus.

Aber was genau bedeutet „Tritt hierbei ein Fehler“?

Schau dir nochmal die Fehlermeldung an, die du bekommen hast als du es mit einer Division durch Null versucht hast.

Java Exception ArithmeticException

Gleich in der ersten Zeile steht der Name, der Java Exception, die geworfen wurde.

Aha! Eine Division durch Null erzeugt also eine sogenannte ArithmeticException, die wir in Zeile fünf mit Hilfe des Schlüsselwortes catch abfangen können.

Was ist daran so toll?

Ich weiß was du denkst. Wirklich einfacher ist das nicht und Tipparbeit haben wir uns auch nicht erspart.

Im Gegenteil, der Programmcode, in dem wir die Division durch Null mit Hilfe einer if Bedingung abgefangen haben ist sogar kompakter.

Also was soll das ganze Theater?

Ja, schon!

Aber du darfst hierbei eines nicht vergessen.

Wir haben uns der Verdeutlichung wegen auf einen einzigen Fall beschränkt, bei dem eine ArithmeticException ausgelöst wird.

Doch außer einer Division durch Null, gibt es noch viele andere Fälle die mathematisch nicht möglich sind, wie z.B. das Ziehen einer Quadratwurzel aus einer negativen Zahl. Und alle diese Fälle kannst du mit einer einzigen Exception, nämlich der ArithmeticException abfangen.

Aufgabe einer Java Exception ist es nicht nur einen konkreten Fehler zu behandeln, sondern gleich auf eine ganze Klasse von Fehlern einheitlich zu reagieren.

Selbstverständlich gibt es neben der Behandlung von arithmetischen Ausnahmen noch viele weitere Klassen von Exceptions.

So kannst du beispielsweise mit Hilfe der IOException Ausnahmen behandeln, die beim Lesen oder Schreiben von Daten auftreten können.

Du kannst dir das vorstellen wie eine Warnlampe im Auto.

Java Exception Verkettung

In vielen Autos gibt es eine Warnleuchte, die auf mögliche Bremsprobleme hinweist. Hierbei ist aber egal woher diese genau kommen.

Die Lampe leuchtet auf, sobald ein Problem festgestellt wird, ob es sich um fehlende Bremsflüssigkeit oder verschlissene Bremsscheiben handelt ist egal.

Ein Bremswarnlicht verarbeitet die Fehlerklasse aller Bremsprobleme.

Mehrere Ausnahmen auf einmal behandeln

Manchmal passieren Katastrophen.

Dann sind viele Probleme gleichzeitig zu behandeln. Aber auch das ist nicht schwer, denn wir haben die Möglichkeit mehrere catch Anweisungen nacheinander zu schalten.

Schauen wir uns dazu folgendes Beispiel an:

1: public static int berechneDivisionEingabe(){
2:	int a = 0;
3:	int b = 0;
4:	int c = 0;
5:	Scanner scan = new Scanner(System.in);
6:	try{
7:	    a = scan.nextInt();
8:	    b = scan.nextInt();
9:	    c = a/b;
10:	}catch(InputMismatchException e){
11:			System.out.println("Fehler");
12:	}catch(ArithmeticException e){
13:			System.out.println("Fehler 2");
14:	}
15:	return c;
16: }

Was passiert hier?

In den Zeilen zwei bis vier deklarieren wir zunächst drei Integer Variablen.

Anschließend weisen wir im try Block den Variablen a und b (Zeile 7 und 8) Benutzereingaben zu, die wir mit Hilfe eines Scanners über eine Bildschirm-Eingabe des Anwenders erhalten.

Die Variable c speichert dann den Quotient aus a und b.

Welche Java Exceptions können hier auftreten?

Natürlich kann der Anwender auch hier, durch Eingabe einer 0, eine Division durch Null auslösen, die wir, wie gewohnt mit einer ArithmeticException abfangen (Zeile 12) können.

Aber was passiert, wenn die Eingabedaten des Anwenders nicht vom Typ Integer sind?

Ich schlage einen Testlauf vor!

Wie reagiert das Programm, wenn wir als ersten Wert den String fuenf einlesen?

In diesem Fall löst die nextInt() Methode in Zeile sieben eine InputMismatch Exception aus, die innerhalb des catch Blocks in Zeile zehn mit der Bildschirmausgabe

Fehler

abgefangen wird.

Wir können also mehrere Java Exceptions in einer Kaskade von catch Anweisungen innerhalb einer try-catch Anweisung abfangen.

Kontrollierter Ausstieg mit finally

Stell dir eine Kreissäge vor! Mit der du eine Holzplatte zersägst. Plötzlich triffst du auf einen Stahlnagel, an dem du hängen bleibst.

Java Exceptions finally

Was muss auf jeden Fall passieren?

Richtig! Wir müssen sicherstellen, dass egal was geschieht der Motor stehen bleibt.

Und genau das können wir in Java mit Hilfe des Schlüsselwortes finally erreichen.

Mit Hilfe von finally sorgen wir dafür, dass sich ein Objekt nach auftreten eines Fehlers in einem definierten Zustand befindet.

Schauen wir uns auch das anhand eines Beispiels an und wandeln unsere Methode berechneDivisionEingabe von oben leicht ab.

1: public static int berechneDivisionEingabe(){
2:	int a = 0;
3:	int b = 0;
4:	int c = 0;
5:	Scanner scan = new Scanner(System.in);
6:	try{
7:	    a = scan.nextInt();
8:	    b = scan.nextInt();
9:	    c = a/b;
10:	}catch(ArithmeticException e){
11:		System.out.println("Fehler 2");
12:	}finally{
13:		System.out.println("Danke und Tschüss!");
14:	}
15:     System.out.println("Funktion beendet!");
17:	return c;
18: }

Zum einen haben wir die InputMismatchException Java Exception entfernt und zum anderen einen finally Block (Zeile 12) und eine Bildschirmausgabe hinzugefügt (Zeile 15), die ausgegeben wird sobald das Ende der Methode erreicht ist.

Machen wir zwei Probeläufe:

1.) Wir bilden den Quotient aus a = 10 und b = 2.

Unsere Eingabedaten sind beides Integer-Werte ungleich Null, weshalb es zu keiner Exception kommt. Die Programmausgabe ist folgende:

1: Danke und Tschüss!
2: Funktion beendet!
3: 5

In der ersten Zeile steht die Bildschirmausgabe, die wir innerhalb des finally Blocks ausgeben. Zeile zwei beweist, dass die Funktion vollständig abgearbeitet wurde. Und zu guter letzt erhalten wir noch das Ergebnis der Division von 10 durch 2.

Also keine Überraschungen! Machen wir einen weiteren Test. Diesmal aber mit Fehlerhaften Eingabedaten.

Wir bilden den Quotient aus a = Hans und b = 2

Jetzt ist a kein Integer-Wert mehr, weshalb eine InputMismatchException geworfen wird, die wir nicht abfangen, weshalb die Programmausgabe wie folgt aussieht.

Danke und Tschüss!
Exception in thread "main" java.util.InputMismatchException

Wie wir sehen erhalten wir auch hier wieder die Bildschirmausgabe aus dem finally Block.

Aber merkst du was fehlt? Wir erhalten diesmal keine Meldung Funktion beendet!.

Die Java Exception, welche durch die Zuweisung in Zeile sieben geworfen wird, führt also offenbar dazu, dass die Methode nicht vollständig abgearbeitet wird. Trotzdem wird der Code hinter finally ausgeführt.

Also merke: Der Code hinter dem Schlüsselwort finally wird auf jeden Fall ausgeführt. Und zwar unabhängig davon, ob der Code im try eine Exception geworfen hat oder nicht.

Im folgenden Video erkläre ich dir wie du das gelernte in Eclipse umsetzt.

Java Exceptions werfen mit Hilfe des Schlüsselwortes throw

Bisher haben wir immer nur reagiert! So hat z.B. die Methode nextInt() des Scanner Objekts eine Exception für uns geworfen, sobald der Anwender einen anderen Datentypen als ein Integer-Wert eingegeben hat.

Aber wie können wir selber eine Exception werfen, und auf diese Weise auf Dinge reagieren, die uns nicht passen?

Hierfür gibt es das Schlüsselwort throw.

Zur Demonstration wieder eine leichte Anpassung der berechneDivision() Methode.

1: public static int berechneDivision(int a, int b){
2:	if (b == 0){
3:	    throw new IllegalArgumentException("Der Nenner darf nicht Null sein");
4:	}
5:	int c = a/b;
6:	return c;
7:}

Wieder geht es um das Problem eine Division durch Null zu vermeiden.

Diesmal verlassen wir uns aber nicht auf die automatisch ausgelöste ArithmeticException, sondern behandeln eine Division durch Null mit Hilfe einer IllegalArgumentException indem wir eine Instanz dieser Ausnahme erzeugen und mittels des Schlüsselworts throw (Zeile drei) auswerfen.

Der Konstruktor erwartet als Argument die Fehlermeldung, die ausgegeben werden soll, wenn die Java Exception geworfen wird.

Also los! Versuchen wir uns an einer Division durch Null.

Exception in thread "main" java.lang.IllegalArgumentException: Der Nenner darf nicht Null sein

Sauber! Wir erhalten wie gewünscht eine IllegalArgumentException, welche wir beim Aufruf der berechneDivision() wie gewohnt in einer try-catch Kontrollstruktur abfangen können.

try{
	System.out.println(berechneDivision(10,0));
}catch(IllegalArgumentException e){
	System.out.println("Fehler");
}

Der wirkliche Nutzen dieser Möglichkeit wird erst deutlich, wenn wir eigene Java Exceptions entwerfen. Und wie das geht, darum kümmern wir uns im nächsten Teil dieser Artikelserie!

Fazit: Eine Java Exception ist eine sehr elegante Möglichkeit um in deinen Programmen mit unvorhersehbaren Situationen umzugehen.

Wie immer freue ich mich über deine Fragen im Kommentarbereich!

Hat dir der Artikel gefallen? Dann folge uns doch am besten gleich auf Facebook!

Hallo ich bin Kim und ich möchte ein großer Programmierer werden. Machst du mit?

Kommentare (10)

  • Antworte

    Sehr hilfreich. Vielen Dank. In der Schule bringt man uns so etwas nicht mehr bei, sondern diktiert uns mehr oder weniger fehlerfreien Code…

    • Hi Lena, ich danke dir! Exceptions sind in JAVA recht wichtig, da du damit auch auf unvorhersehbare Sachen, wie einen Server Absturz reagieren kannst. Viele Grüße Kim

  • Antworte

    Sehr nützlich und gut erklärt.
    Vielen Dank für die Erklärung.

    Gruß
    Nico

    • Hi Nico, viele Dank für dein Feedback. Freue mich wenn ich weiterhelfen kann. Viele Grüße Kim

  • Antworte

    Ich musste kurz mein Java Wissen nach der langen vorlesungsfreien Zeit auffrischen und da kamen deine Beiträge dazu genau richtig!
    Sehr gut erklärt. 🙂
    LG Karina

    • Vielen Dank! Viele Grüße Kim

  • Antworte

    Hallo Kim,
    vielen Dank für deinen Hilfreichen Beitrag!
    Kurze Frage: nach einem throw new ist kein return nötig, da sobald der Fall einer Fehlermeldung eintritt, die Methode wie beim return verlassen wird oder?

    • Hallo Niko, ja, korrekt. Bei einem throw wird die Methode verlassen. Viele Grüße Kim

  • Antworte

    Die 1. Abblidung im Absatz Ausnahmebehandlung mit Hilfe der try-catch Kontrollstruktur ist falsch. Return darf nicht in try oder catch sein, sonst erkennt die Methode das nicht und musst einen neuen return einfügen. Es geht aber wenn du return außerhalb der Klammern hast dann muss es funktionieren. So schlecht.

    • Hallo, vielen Dank für den Hinweis. Der Code in dieser Abbildung war in der Tat nicht lauffähig. Allerdings nicht weil ein return in einem try oder catch Block nicht erlaubt ist, sondern weil jede Methode mit Rückgabewert auf jeden Fall eine return Anweisung ausführen muss und das war hier im Fehlerfall nicht gegeben. Das ist vergleichbar mit der Situation, dass wir ein return in eine if-Anweisung packen. Viele Grüße Kim

Antworte auf Nico Abbruch