From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001
From: Sven Eisenhauer
+Das Behandeln von Ausnahmen erfolgt mit Hilfe der try-catch-Anweisung:
+
+
+
+
+
+
+ Titel
+ Inhalt
+ Suchen
+ Index
+ DOC
+ Handbuch der Java-Programmierung, 5. Auflage
+
+ <<
+ <
+ >
+ >>
+ API
+ Kapitel 12 - Exceptions
+
+
+
+
+
+12.2 Behandlung von Exceptions
+
+
+
+
+
+
+
+12.2.1 Die try-catch-Anweisung
+
+
+
+
+Listing 12.1: Die try-catch-Anweisung
+
+
+
+
+
+001 try {
+002 Anweisung;
+003 ...
+004 } catch (Ausnahmetyp x) {
+005 Anweisung;
+006 ...
+007 }
+
+
+Der try-Block +enthält dabei eine oder mehrere Anweisungen, bei deren Ausführung +ein Fehler des Typs Ausnahmetyp +auftreten kann. In diesem Fall wird die normale Programmausführung +unterbrochen, und der Programmablauf fährt mit der ersten Anweisung +nach der catch-Klausel +fort, die den passenden Ausnahmetyp deklariert hat. Hier kann nun +Code untergebracht werden, der eine angemessene Reaktion auf den Fehler +realisiert. + +
+Wir wollen das folgende fehlerhafte Programm betrachten: + + +
+
+
+
+001 /* RTErrorProg1.java */
+002
+003 public class RTErrorProg1
+004 {
+005 public static void main(String[] args)
+006 {
+007 int i, base = 0;
+008
+009 for (base = 10; base >= 2; --base) {
+010 i = Integer.parseInt("40",base);
+011 System.out.println("40 base "+base+" = "+i);
+012 }
+013 }
+014 }
+
+ |
++RTErrorProg1.java | +
+Hier soll der String »40« aus verschiedenen Zahlensystemen
+in ein int
+konvertiert und als Dezimalzahl ausgegeben werden. Die dazu verwendete
+Methode parseInt
+überprüft, ob der übergebene String einen gültigen
+Zahlenwert zur angegebenen Basis darstellt. Ist dies nicht der Fall,
+löst sie eine Ausnahme des Typs NumberFormatException
+aus. Ohne weitere Maßnahmen stürzt das Programm dann beim
+Versuch, den String »40« als Zahl zur Basis 4 anzusehen,
+ab:
+
+
+40 base 10 = 40
+40 base 9 = 36
+40 base 8 = 32
+40 base 7 = 28
+40 base 6 = 24
+40 base 5 = 20
+Exception in thread "main" java.lang.NumberFormatException: 40
+ at java.lang.Integer.parseInt(Compiled Code)
+ at RTErrorProg1.main(Compiled Code)
+
+
+
+
+Das Programm läßt sich nun leicht gegen solche Fehler absichern, +indem die Programmsequenz, die den Fehler verursacht, in eine try-catch-Anweisung +eingeschlossen wird: + + +
+
+
+
+001 /* Listing1203.java */
+002
+003 public class Listing1203
+004 {
+005 public static void main(String[] args)
+006 {
+007 int i, base = 0;
+008
+009 try {
+010 for (base = 10; base >= 2; --base) {
+011 i = Integer.parseInt("40",base);
+012 System.out.println("40 base "+base+" = "+i);
+013 }
+014 } catch (NumberFormatException e) {
+015 System.out.println(
+016 "40 ist keine Zahl zur Basis "+base
+017 );
+018 }
+019 }
+020 }
+
+ |
++Listing1203.java | +
+Zwar ist 40 immer noch keine Zahl zur Basis 4, aber das Programm fängt
+diesen Fehler nun ab und gibt eine geeignete Fehlermeldung aus:
+
+
+40 base 10 = 40
+40 base 9 = 36
+40 base 8 = 32
+40 base 7 = 28
+40 base 6 = 24
+40 base 5 = 20
+40 ist keine Zahl zur Basis 4
+
+
+
+
+
+
+
+In der catch-Klausel +wird nicht nur die Art des abzufangenden Fehlers definiert, sondern +auch ein formaler Parameter angegeben, der beim Auftreten der Ausnahme +ein Fehlerobjekt übernehmen soll. Fehlerobjekte sind dabei Instanzen +der Klasse Throwable +oder einer ihrer Unterklassen. Sie werden vom Aufrufer der Ausnahme +erzeugt und als Parameter an die catch-Klausel +übergeben. Das Fehlerobjekt enthält Informationen über +die Art des aufgetretenen Fehlers. So liefert beispielsweise die Methode +getMessage +einen Fehlertext (wenn dieser explizit gesetzt wurde), und printStackTrace +druckt einen Auszug aus dem Laufzeit-Stack. Am einfachsten kann der +Fehlertext mit der Methode toString +der Klasse Throwable +ausgegeben werden: +
+
+
++public String getMessage() + +public void printStackTrace() + +public String toString() ++ + |
++java.lang.Throwable | +
+Unser Beispielprogramm könnte dann wie folgt umgeschrieben werden: + + +
+
+
+
+001 /* RTErrorProg2.java */
+002
+003 public class RTErrorProg2
+004 {
+005 public static void main(String[] args)
+006 {
+007 int i, base = 0;
+008
+009 try {
+010 for (base = 10; base >= 2; --base) {
+011 i = Integer.parseInt("40",base);
+012 System.out.println("40 base "+base+" = "+i);
+013 }
+014 } catch (NumberFormatException e) {
+015 System.out.println("***Fehler aufgetreten***");
+016 System.out.println("Ursache: "+e.getMessage());
+017 e.printStackTrace();
+018 }
+019 }
+020 }
+
+ |
++RTErrorProg2.java | +
+Die Ausgabe des Programms wäre dann:
+
+
+40 base 10 = 40
+40 base 9 = 36
+40 base 8 = 32
+40 base 7 = 28
+40 base 6 = 24
+40 base 5 = 20
+***Fehler aufgetreten***
+Ursache: 40
+java.lang.NumberFormatException: 40
+ at java.lang.Integer.parseInt(Compiled Code)
+ at RTErrorProg2.main(Compiled Code)
+
+
+
+
+Wie man sieht, ähnelt die Ausgabe des Programms der ersten Version, +die ohne expliziten Fehler-Handler geschrieben wurde. Das liegt daran, +dass das Java-Laufzeitsystem beim Auftreten eines Fehlers, der von +keiner Methode behandelt wurde, printStackTrace +aufruft, bevor es das Programm beendet. + + + + +
+Alle Laufzeitfehler in Java sind Unterklassen der Klasse Throwable. +Throwable +ist eine allgemeine Fehlerklasse, die im wesentlichen eine Klartext-Fehlermeldung +speichern und einen Auszug des Laufzeit-Stacks ausgeben kann. Unterhalb +von Throwable +befinden sich zwei große Vererbungshierarchien: +
+Viele Pakete der Java-Klassenbibliothek definieren ihre eigenen Fehlerklassen. +So gibt es spezielle Fehlerklassen für die Dateiein- und -ausgabe, +die Netzwerkkommunikation oder den Zugriff auf Arrays. Wir werden +diese speziellen Fehlerklassen immer dann erläutern, wenn eine +Methode besprochen wird, die diese Art von Fehler erzeugt. + + + + +
+Die Reaktion auf eine Ausnahme muss keinesfalls zwangsläufig +darin bestehen, das Programm zu beenden. Statt dessen kann auch versucht +werden, den Fehler zu beheben oder zu umgehen, um dann mit dem Programm +fortzufahren. Wird im obigen Programm die try-catch-Anweisung +in die Schleife gesetzt, so fährt das Programm nach jedem Fehler +fort und versucht, die Konvertierung zur nächsten Basis vorzunehmen: + + +
+
+
+
+001 /* Listing1205.java */
+002
+003 public class Listing1205
+004 {
+005 public static void main(String[] args)
+006 {
+007 int i, base = 0;
+008
+009 for (base = 10; base >= 2; --base) {
+010 try {
+011 i = Integer.parseInt("40",base);
+012 System.out.println("40 base "+base+" = "+i);
+013 } catch (NumberFormatException e) {
+014 System.out.println(
+015 "40 ist keine Zahl zur Basis "+base
+016 );
+017 }
+018 }
+019 }
+020 }
+
+ |
++Listing1205.java | +
+Die Ausgabe des Programms lautet nun:
+
+
+40 base 10 = 40
+40 base 9 = 36
+40 base 8 = 32
+40 base 7 = 28
+40 base 6 = 24
+40 base 5 = 20
+40 ist keine Zahl zur Basis 4
+40 ist keine Zahl zur Basis 3
+40 ist keine Zahl zur Basis 2
+
+
+
+
![]() |
+
+
+ +Ob es sinnvoller ist, nach einem Fehler mit der Programmausführung +fortzufahren oder das Programm abzubrechen, ist von der Art des Fehlers +und der Stelle im Programm, an der er aufgetreten ist, abhängig. +Hier muss von Fall zu Fall entschieden werden, wie vorgegangen werden +soll. |
+
+
|
+![]() |
+
+Bisher sind wir davon ausgegangen, dass innerhalb eines try-Blocks +nur eine Ausnahme auftreten kann. Tatsächlich ist es natürlich +ohne weiteres möglich, dass zwei oder mehrere unterschiedliche +Ausnahmen ausgelöst werden. Das Programm kann auf verschiedene +Fehler reagieren, indem es mehr als eine catch-Klausel +verwendet. Jede catch-Klausel +fängt die Fehler ab, die zum Typ des angegebenen Fehlerobjekts +zuweisungskompatibel sind. Dazu gehören alle Fehler der angegebenen +Klasse und all ihrer Unterklassen (das wichtige Konzept der Zuweisungskompatibilität +von Objekttypen wurde in Abschnitt 7.1.6 +erläutert). Die einzelnen catch-Klauseln +werden in der Reihenfolge ihres Auftretens abgearbeitet. + +
+Wir wollen das Beispielprogramm nun so erweitern, dass nicht nur ein +einzelner String in eine Zahl konvertiert wird, sondern ein Array +von Strings. Aufgrund eines Fehlers in der verwendeten for-Schleife +verursacht das Programm einen Zugriff auf ein nicht vorhandenes Array-Element +und löst damit eine Ausnahme des Typs IndexOutOfBoundsException +aus. Diese kann zusammen mit der Ausnahme NumberFormatException +in einer gemeinsamen try-catch-Anweisung +behandelt werden: + + +
+
+
+
+001 /* Listing1206.java */
+002
+003 public class Listing1206
+004 {
+005 public static void main(String[] args)
+006 {
+007 int i, j, base = 0;
+008 String[] numbers = new String[3];
+009
+010 numbers[0] = "10";
+011 numbers[1] = "20";
+012 numbers[2] = "30";
+013 try {
+014 for (base = 10; base >= 2; --base) {
+015 for (j = 0; j <= 3; ++j) {
+016 i = Integer.parseInt(numbers[j],base);
+017 System.out.println(
+018 numbers[j]+" base "+base+" = "+i
+019 );
+020 }
+021 }
+022 } catch (IndexOutOfBoundsException e1) {
+023 System.out.println(
+024 "***IndexOutOfBoundsException: " + e1.toString()
+025 );
+026 } catch (NumberFormatException e2) {
+027 System.out.println(
+028 "***NumberFormatException: " + e2.toString()
+029 );
+030 }
+031 }
+032 }
+
+ |
++Listing1206.java | +
+Die Ausgabe des Programms ist nun:
+
+
+10 base 10 = 10
+20 base 10 = 20
+30 base 10 = 30
+***IndexOutOfBoundsException: java.lang.ArrayIndexOutOfBoundsException
+
+
+
+
+
+
+
+Die try-catch-Anweisung +enthält einen optionalen Bestandteil, der bisher noch nicht erläutert +wurde. Mit Hilfe der finally-Klausel, +die als letzter Bestandteil einer try-catch-Anweisung +verwendet werden darf, kann ein Programmfragment definiert werden, +das immer dann ausgeführt wird, wenn die zugehörige try-Klausel +betreten wurde. Dabei spielt es keine Rolle, welches Ereignis +dafür verantwortlich war, dass die try-Klausel +verlassen wurde. Die finally-Klausel +wird insbesondere dann ausgeführt, wenn der try-Block +durch eine der folgenden Anweisungen verlassen wurde: +
+
![]() |
+
+
+ +Die finally-Klausel +ist also der ideale Ort, um Aufräumarbeiten durchzuführen. +Hier können beispielsweise Dateien geschlossen oder Ressourcen +freigegeben werden. |
+
+
|
+![]() |
+
+Die folgende Variation unseres Beispielprogramms benutzt finally +dazu, am Ende des Programms eine Meldung auszugeben: + + +
+
+
+
+001 /* Listing1207.java */
+002
+003 public class Listing1207
+004 {
+005 public static void main(String[] args)
+006 {
+007 int i, base = 0;
+008
+009 try {
+010 for (base = 10; base >= 2; --base) {
+011 i = Integer.parseInt("40",base);
+012 System.out.println("40 base "+base+" = "+i);
+013 }
+014 } catch (NumberFormatException e) {
+015 System.out.println(
+016 "40 ist keine Zahl zur Basis "+base
+017 );
+018 } finally {
+019 System.out.println(
+020 "Sie haben ein einfaches Beispiel " +
+021 "sehr glücklich gemacht."
+022 );
+023 }
+024 }
+025 }
+
+ |
++Listing1207.java | +
+Die Ausgabe des Programms ist:
+
+
+40 base 10 = 40
+40 base 9 = 36
+40 base 8 = 32
+40 base 7 = 28
+40 base 6 = 24
+40 base 5 = 20
+40 ist keine Zahl zur Basis 4
+Sie haben ein einfaches Beispiel sehr glücklich gemacht.
+
+
+
| Titel + | Inhalt + | Suchen + | Index + | DOC + | Handbuch der Java-Programmierung, 5. Auflage, Addison +Wesley, Version 5.0.1 + |
| << + | < + | > + | >> + | API + | © 1998, 2007 Guido Krüger & Thomas +Stark, http://www.javabuch.de + |