Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger

 << zurück
Java ist auch eine Insel von Christian Ullenboom
Programmieren für die Java 2-Plattform in der Version 5
Java ist auch eine Insel

Java ist auch eine Insel
5., akt. und erw. Auflage
1454 S., mit CD, 49,90 Euro
Galileo Computing
ISBN 3-89842-747-1
gp Kapitel 7 Exceptions
  gp 7.1 Problembereiche einzäunen
    gp 7.1.1 Exceptions in Java mit try und catch
    gp 7.1.2 Eine Datei auslesen mit RandomAccessFile
    gp 7.1.3 Ablauf einer Ausnahmesituation
    gp 7.1.4 Wiederholung kritischer Bereiche
    gp 7.1.5 throws im Methodenkopf angeben
    gp 7.1.6 Abschließende Arbeiten mit finally
    gp 7.1.7 Nicht erreichbare catch-Klauseln
  gp 7.2 Die Klassenhierarchie der Fehler
    gp 7.2.1 Die Exception-Hierarchie
    gp 7.2.2 Oberausnahmen fangen
    gp 7.2.3 Alles geht als Exception durch
    gp 7.2.4 RuntimeException muss nicht aufgefangen werden
    gp 7.2.5 Harte Fehler: Error
  gp 7.3 Werfen eigener Exceptions
    gp 7.3.1 Mit throw Ausnahmen auslösen
    gp 7.3.2 Typecast auf ein null-Objekt für eine NullPointerException
    gp 7.3.3 Neue Exception-Klassen definieren
    gp 7.3.4 Geschachtelte Ausnahmen
  gp 7.4 Rückgabewerte bei ausgelösten Ausnahmen
  gp 7.5 Der Stack Trace
    gp 7.5.1 Stack Trace aus Throwable
    gp 7.5.2 Stack Trace aus Thread
  gp 7.6 Assertions
    gp 7.6.1 Assertions in Java
    gp 7.6.2 Assertions in eigenen Programmen nutzen
    gp 7.6.3 Assertions aktivieren


Galileo Computing

7.2 Die Klassenhierarchie der Fehledowntop

Eine Exception ist ein Objekt, welches direkt oder indirekt von java.lang.Throwable abgeleitet ist. Von dort aus verzweigt sich die Hierarchie der Fehlerarten nach java.lang. Exception und java.lang.Error. Die Klassen, die aus Error hervorgehen, sollen nicht weiterverfolgt werden. Es handelt sich hierbei um Fehler, die so schwerwiegend sind, dass sie zur Beendigung des Programms führen und vom Programmierer nicht weiter beachtet werden müssen und sollen. Throwable vererbt eine Reihe von nützlichen Methoden, die in der folgenden Grafik sichtbar sind. Sie fasst gleichzeitig die Vererbungsbeziehungen noch einmal zusammen.

Abbildung
Hier klicken, um das Bild zu Vergrößern


Galileo Computing

7.2.1 Die Exception-Hierarchie  downtop

Jede Benutzerausnahme wird von java.lang.Exception abgeleitet. Die Exceptions sind Fehler oder Ausnahmesituationen, die vom Programmierer behandelt werden sollen. Die Klasse Exceptions teilt sich dann nochmals in weitere Unterklassen beziehungsweise Unterhierarchien auf. Die folgende Grafik zeigt einige Unterklassen der Klasse Exception:

Abbildung
Hier klicken, um das Bild zu Vergrößern


Galileo Computing

7.2.2 Oberausnahmen fangen  downtop

Eine Konsequenz der Hierarchien ist, dass es ausreicht, einen Fehler der Oberklasse aufzufangen. Wenn zum Beispiel eine FileNotFoundException auftritt, dann ist diese Klasse von IOException abgeleitet, was bedeutet, dass FileNotFoundException eine Spezialisierung ist. Wenn wir alle IOException auffangen, behandeln wir damit auch gleichzeitig die FileNotFoundException mit.

Erinnern wir uns noch einmal an das Dateibeispiel. Dort haben wir eine FileNotFound-Exception und eine IOException einzeln behandelt. Dies lässt sich wie folgt zusammenfassen:

Listing 7.7   ReadFileWithRAFShort.java, main()

RandomAccessFile f = null;
try
{
  f = new RandomAccessFile( "c:/winnt/desktop.ini""r" );
  for ( String line; (line=f.readLine()) != null; )
    System.out.println( line );
}
  catch ( IOException e )
{
  System.err.println( "Ein/Ausgabe-Probleme." );
}
  finally
{
  if ( f != null )
    try { f.close(); } catch ( IOException e ) { e.printStackTrace(); }
}

Angst davor, dass wir den Fehlertyp später nicht mehr unterscheiden können, brauchen wir nicht zu haben, denn die an die catch-Anweisung gebundenen Variablen können wir mit instanceof weiter verfeinern. Doch aus Gründen der Übersichtlichkeit sollte diese Technik sparsam angewendet werden. Fehlerarten, die unterschiedlich behandelt werden müssen, verdienen immer getrennte catch-Klauseln. Das trifft zum Beispiel auf FileNotFoundException und IOException zu.

Abbildung
Hier klicken, um das Bild zu Vergrößern


Galileo Computing

7.2.3 Alles geht als Exception durch  downtop

Da Exception die Basisklasse aller Exceptions ist, ließe sich natürlich auch alles mit Exception abfangen. So könnte jemand auf die Idee kommen, aus

try {
  irgendwas Unartiges ...
}
catch ( IllegalAccessException e ) { ... }
catch ( InstantiationException e ) { ... }

eine Optimierung zu versuchen, die etwa so aussieht:

try {
  irgendwas Unartiges ...
}
  catch ( Exception e ) { ... }  

Da der Aufruf in den catch-Blöcken gleich aussieht, ließe sich alles in einer Routine zur Fehlerbehandlung ausführen. Doch dann muss die Oberklasse genommen werden – sozusagen der kleinste gemeinsame Nenner –, und dies ist die Klasse Exception. Doch was für andere Fehlertypen gut funktionieren mag, ist für catch(Exception) gefährlich, weil wirklich jede Ausnahme aufgefangen und in der Ausnahmebehandlung bearbeitet wird. Taucht beispielsweise eine null-Referenz durch eine nicht initialisierte Variable mit Referenztyp auf, so würde dies fälschlicherweise ebenso behandelt.

Auch Nachfolgendes würde durch das Auffangen einer allgemeinen Exception abgefangen werden. Daher ist das Zusammenfassen zur Oberklasse Exception in der Regel keine gute Lösung.

Point p;
p.setX( 2 );    // Nicht initialisiert
int i = 0;
int x = 12/i;   // Division durch Null

Eclipse

Tritt eine Exception auf, so wird sie im Ausgabefenster rot angezeigt. Praktischerweise sind die Fehlermeldungen wie Links: ein Klick, und Eclipse zeigt die Exception-auslösende Zeile.

Abbildung
Hier klicken, um das Bild zu Vergrößern


Galileo Computing

7.2.4 RuntimeException muss nicht aufgefangen werden  downtop

Einige Fehlerarten können potenziell an vielen Programmstellen auftreten, etwa eine Division durch null oder ungültige Indexwerte beim Zugriff auf Array-Elemente. Treten solche Fehler beim Programmlauf auf, liegt in der Regel ein Denkfehler des Programmierers vor, und das Programm sollte normalerweise nicht versuchen, die ausgelöste Ausnahme aufzufangen und zu behandeln. Daher wurde die Unterklasse RuntimeException eingeführt, die Fehler beschreibt, die vom Programmierer behandelt werden können, aber nicht müssen. Sie werden ausgelöst, wenn der Entwickler beispielsweise doch nicht die Division durch null verhindert (ArithmeticException) oder die Indexgrenzen missachtet (IndexOutOf-BoundsExceptions). Der Name »RuntimeException« ist jedoch seltsam gewählt, da alle Ausnahmen immer zur Runtime, also zur Laufzeit erzeugt, ausgelöst und behandelt werden.

Abbildung
Hier klicken, um das Bild zu Vergrößern


Galileo Computing

7.2.5 Harte Fehler: Error  toptop

Fehler, die von der Klasse java.lang.Error abgeleitet sind, stellen Fehler dar, die mit der JVM in Verbindung stehen. Anders dagegen die von Exceptions abgeleiteten Klassen – sie stehen für eigene Programmfehler. Beispiele für konkrete Error-Klassen sind AnnotationFormatError, AssertionError, AWTError, CoderMalfunctionError, FactoryConfigurationError, LinkageError, ThreadDeath, TransformerFactoryConfigurationError, VirtualMachineError (mit den Unterklassen InternalError, OutOfMemoryError, StackOver-flowError, UnknownError). Im Fall von ThreadDeath lässt sich ableiten, dass nicht alle Error-Klassen auf »Error« enden.

Da die Fehler »abnormales« Verhalten anzeigen, müssen sie auch nicht mit einem try/catch-Block aufgefangen werden oder mit throws weiter nach oben gegeben werden.

Listing 7.8   ThrowError.java

public class ThrowError
{
  public static void main( String[] args )
  {
    throw new InternalError();
  }
}

Allerdings ist es möglich, die Fehler mit einem try/catch aufzufangen, da Error-Klassen Unterklassen von Throwable sind und sich daher genauso verhalten. In sofern ist ein Auffangen legitim und auch ein finally ist korrekt. Ob das Auffangen sinnvoll ist, ist eine andere Frage, denn wenn die JVM einen Fehler anzeigt, bleibt offen, wie darauf sinnvoll zu reagieren ist. Was sollten wir bei einer LinkageError machen? Einen OutOfMemoryError in bestimmten Programmteilen aufzufangen, kann jedoch von Vorteil sein. Eigene Unterklassen von Error sollten keine Anwendung finden.

 << zurück




Copyright © Galileo Press GmbH 2005
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de