Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
1 Java ist auch eine Sprache
2 Sprachbeschreibung
3 Klassen und Objekte
4 Der Umgang mit Zeichenketten
5 Mathematisches
6 Eigene Klassen schreiben
7 Angewandte Objektorientierung
8 Exceptions
9 Die Funktionsbibliothek
10 Threads und nebenläufige Programmierung
11 Raum und Zeit
12 Datenstrukturen und Algorithmen
13 Dateien und Datenströme
14 Die eXtensible Markup Language (XML)
15 Grafische Oberflächen mit Swing
16 Grafikprogrammierung
17 Netzwerkprogrammierung
18 Verteilte Programmierung mit RMI und Web-Services
19 JavaServer Pages und Servlets
20 Applets
21 Midlets und die Java ME
22 Datenbankmanagement mit JDBC
23 Reflection und Annotationen
24 Logging und Monitoring
25 Sicherheitskonzepte
26 Java Native Interface (JNI)
27 Dienstprogramme für die Java-Umgebung
A Die Begleit-DVD
Stichwort
Download: - ZIP, ca. 12,5 MB
Buch bestellen
Ihre Meinung?
<< zurück | Galileo Computing / <openbook> /Java-Insel | vor >>
Java ist auch eine Insel von Christian Ullenboom Programmieren mit der Java Standard Edition Version 6
Java ist auch eine Insel 7., aktualisierte Auflage geb., mit DVD (November 2007) 1.492 S., 49,90 Euro Galileo Computing ISBN 978-3-8362-1146-8 |
| 8 Exceptions
|  | 8.1 Problembereiche einzäunen
|  |  | 8.1.1 Exceptions in Java mit try und catch
|  |  | 8.1.2 Eine Datei mit RandomAccessFile auslesen
|  |  | 8.1.3 Ablauf einer Ausnahmesituation
|  |  | 8.1.4 Wiederholung abgebrochener Bereiche
|  |  | 8.1.5 throws im Methodenkopf angeben
|  |  | 8.1.6 Abschlussbehandlung mit finally
|  |  | 8.1.7 Nicht erreichbare catch-Klauseln
|  | 8.2 Die Klassenhierarchie der Fehler
|  |  | 8.2.1 Die Exception-Hierarchie
|  |  | 8.2.2 Oberausnahmen auffangen
|  |  | 8.2.3 Alles geht als Exception durch
|  |  | 8.2.4 RuntimeException muss nicht aufgefangen werden
|  |  | 8.2.5 Harte Fehler: Error
|  | 8.3 Auslösen eigener Exceptions
|  |  | 8.3.1 Mit throw Ausnahmen auslösen
|  |  | 8.3.2 Neue Exception-Klassen deklarieren
|  |  | 8.3.3 Abfangen und Weiterleiten
|  |  | 8.3.4 Geschachtelte Ausnahmen
|  |  | 8.3.5 Rückgabewerte bei ausgelösten Ausnahmen
|  | 8.4 Der Stack-Trace
|  |  | 8.4.1 Stack-Trace erfragen
|  | 8.5 Assertions
|  |  | 8.5.1 Assertions in eigenen Programmen nutzen
|  |  | 8.5.2 Assertions aktivieren
## 8.2 Die Klassenhierarchie der Fehler Eine Exception ist ein Objekt, dessen Typ direkt oder indirekt von java.lang.Throwable abgeleitet ist. (Die Namensgebung mit -able legt eine Schnittstelle nahe, aber Throwable ist eine nicht-abstrakte Klasse.) 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 so schwerwiegende Fehler, 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. Hier klicken, um das Bild zu vergrößern ### 8.2.1 Die Exception-Hierarchie 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: Hier klicken, um das Bild zu vergrößern ### 8.2.2 Oberausnahmen auffangen Eine Konsequenz der Hierarchien besteht darin, dass es ausreicht, einen Fehler der Oberklasse aufzufangen. Wenn zum Beispiel eine FileNotFoundException auftritt, ist diese Klasse von IOException abgeleitet, was bedeutet, dass FileNotFoundException eine Spezialisierung darstellt. 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 FileNotFoundException und eine IOException einzeln behandelt. Dies lässt sich wie folgt zusammenfassen: Listing 8.10 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. Aus Gründen der Übersichtlichkeit sollte diese Technik jedoch sparsam angewendet werden. Fehlerarten, die unterschiedlich behandelt werden müssen, verdienen immer getrennte catch-Klauseln. Das trifft zum Beispiel auf FileNotFoundException und IOException zu. Hier klicken, um das Bild zu vergrößern ### 8.2.3 Alles geht als Exception durch 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 ...
      irgendwas anderes Unartiges ...
    }
    catch ( IllegalAccessException e ) { Behandlung }
    catch ( InstantiationException e ) { Behandlung }
aufgrund der identischen Fehlerbehandlungen eine Optimierung zu versuchen, die etwa so aussieht:
    try {
      irgendwas Unartiges ...
      irgendwas anderes Unartiges ...
    }
    catch ( Exception e ) { Behandlung }
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.
    Point p = null;
    p.setX( 2 );      // Nicht initialisiert
    int i = 0;
    int x = 12 / i;   // Ganzzahlige Division durch 0
Tritt eine Exception auf, so wird sie im Ausgabefenster rot angezeigt. Praktischerweise sind die Fehlermeldungen wie Links: ein Klick, und Eclipse zeigt die Zeile, die die Exception auslöst. Hier klicken, um das Bild zu vergrößern ### 8.2.4 RuntimeException muss nicht aufgefangen werden Einige Fehlerarten können potenziell an vielen Programmstellen auftreten, etwa eine ganzzahlige Division durch Null [Fließkommadivisionen durch 0.0 ergeben entweder ± unendlich oder NaN. ] 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. Der Name »RuntimeException« ist jedoch seltsam gewählt, da alle Ausnahmen immer zur Runtime, also zur Laufzeit, erzeugt, ausgelöst und behandelt werden. Tabelle 8.1 listet einige bekannte Fehlertypen auf.
Tabelle 8.1 Einige RuntimeException-Klassen
Unterklasse von RuntimeException | Was den Fehler auslöst
ArithmeticException | Ganzzahlige Division durch 0.
ArrayIndexOutOfBoundsExceptions | Indexgrenzen missachtet, etwa durch (new int[0])[1]. Eine ArrayIndexOutOfBoundsExceptions ist neben StringIndexOutOfBoundsException eine Unterklasse von IndexOutOfBoundsException.
ClassCastException | Typanpassung ist zur Laufzeit nicht möglich. So löst (java.util.Stack) new java.util.Vector() eine ClassCastException mit der Meldung »java.util.Vector cannot be cast to java.util.Stack« aus.
EmptyStackException | Stapelspeicher ist leer. Die Anweisung new java.util.Stack().pop(); provoziert den Fehler.
IllegalArgumentException | Eine häufig verwendete Ausnahme, mit der Methoden falsche Argumente melden. Die Anweisung Integer .parseInt("tutego"); löst eine NumberFormatException, eine Unterklasse von IllegalArgumentException, aus.
IllegalMonitorStateException | Thread möchte warten, hat aber den Monitor nicht. Ein Beispiel: new String().wait();
NullPointerException | Meldet einer der häufigsten Programmierfehler, beispielsweise durch ((String) null).length().
UnsupportedOperationException | Operationen sind nicht gestattet. Etwa durch java.util.Arrays.asList(args).add("chris");
Eine RuntimeException muss der Entwickler nicht abfangen, kann er aber. Da der Compiler nicht auf ein Abfangen besteht, heißen die aus RuntimeException hervorgegangen Ausnahmen auch nicht geprüfte Ausnahmen (engl. unchecked exceptions) und alle übrigen geprüfte Ausnahmen (engl. checked exceptions). Auch muss eine RuntimeException nicht unbedingt bei throws in der Methodensignatur angegeben werden, wobei einige Autoren das zur Dokumentation machen. Tritt eine RuntimeException zur Laufzeit auf, und kommt nicht irgendwann in der Aufrufhierarchie ein try-catch, wird der ausführende Thread beendet. Löst also eine in main() aufgerufene Aktion eine RuntimeException aus, ist das das Ende für dieses Hauptprogramm. ### 8.2.5 Harte Fehler: Error Fehler, die von der Klasse java.lang.Error abgeleitet sind, stellen Fehler dar, die mit der JVM in Verbindung stehen. Anders dagegen die von Exception 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, StackOverflowError, UnknownError). Im Fall von ThreadDeath lässt sich ableiten, dass nicht alle Error-Klassen auf »Error« enden. Das liegt sicherlich auch daran, dass das nicht ein Fehler im eigentlichen Sinne ist, denn die JVM löst ThreadDeath aus, wenn das Programm ein Thread mit stop() beenden will. Da die Fehler »abnormales« Verhalten anzeigen, müssen sie auch nicht mit einem try-catch-Block aufgefangen oder mit throws nach oben weitergegeben werden. (Sun zählt sie daher auch zu den nicht geprüften Ausnahmen, obwohl Error keine Unterklasse von RuntimeException ist!) Allerdings ist es möglich, die Fehler aufzufangen, da Error-Klassen Unterklassen von Throwable sind und sich daher genauso behandeln lassen. Insofern 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 einem LinkageError tun? Einen OutOfMemoryError in bestimmten Programmteilen aufzufangen, kann jedoch von Vorteil sein. Eigene Unterklassen von Error sollten keine Anwendung finden. Glücklicherweise sind die Klassen aber nur Unterklassen von Throwable und nicht von Exception, so dass ein catch(Exception e) nicht aus Versehen Dinge wie ThreadDeath abfängt, die eigentlich nicht behandelt gehören. ### Ihr Kommentar Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.
Name |
E-Mail |
Ihr Kommentar |
<< zurück | <top> | vor >>

Copyright © Galileo Press 2008
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, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de