Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
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 Generics, innere Klassen
10 Die Klassenbibliothek
11 Threads und nebenläufige Programmierung
12 Datenstrukturen und Algorithmen
13 Raum und Zeit
14 Dateien und Datenströme
15 Die eXtensible Markup Language (XML)
16 Grafische Oberflächen mit Swing
17 Grafikprogrammierung
18 Netzwerkprogrammierung
19 Verteilte Programmierung mit RMI und Web–Services
20 JavaServer Pages und Servlets
21 Applets
22 Midlets und die Java ME
23 Datenbankmanagement mit JDBC
24 Reflection und Annotationen
25 Logging und Monitoring
26 Sicherheitskonzepte
27 Java Native Interface (JNI)
28 Dienstprogramme für die Java-Umgebung
Stichwort

Download:
- ZIP, ca. 14,1 MB
Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java ist auch eine Insel (8. Auflage) von Christian Ullenboom
Programmieren mit der Java Standard Edition Version 6
Buch: Java ist auch eine Insel (8. Auflage)

Java ist auch eine Insel (8. Aufl.)
8., aktual. Auflage, geb., mit DVD
1.475 S., 49,90 Euro
Galileo Computing
ISBN 978-3-8362-1371-4
Pfeil 8 Exceptions
Pfeil 8.1 Problembereiche einzäunen
Pfeil 8.1.1 Exceptions in Java mit try und catch
Pfeil 8.1.2 Eine Datei mit RandomAccessFile auslesen
Pfeil 8.1.3 Ablauf einer Ausnahmesituation
Pfeil 8.1.4 Wiederholung abgebrochener Bereiche
Pfeil 8.1.5 throws im Methodenkopf angeben
Pfeil 8.1.6 Abschlussbehandlung mit finally
Pfeil 8.1.7 Nicht erreichbare catch-Klauseln
Pfeil 8.2 Die Klassenhierarchie der Fehler
Pfeil 8.2.1 Die Exception-Hierarchie
Pfeil 8.2.2 Oberausnahmen auffangen
Pfeil 8.2.3 Alles geht als Exception durch
Pfeil 8.2.4 RuntimeException muss nicht aufgefangen werden
Pfeil 8.2.5 Harte Fehler: Error
Pfeil 8.3 Auslösen eigener Exceptions
Pfeil 8.3.1 Mit throw Ausnahmen auslösen
Pfeil 8.3.2 Neue Exception-Klassen deklarieren
Pfeil 8.3.3 Abfangen und Weiterleiten
Pfeil 8.3.4 Geschachtelte Ausnahmen
Pfeil 8.4 Rückgabewerte bei ausgelösten Ausnahmen
Pfeil 8.5 Der Stack-Trace
Pfeil 8.5.1 Stack-Trace erfragen
Pfeil 8.6 Assertions
Pfeil 8.6.1 Assertions in eigenen Programmen nutzen
Pfeil 8.6.2 Assertions aktivieren

»Wir sind in Sicherheit! Er kann uns nicht erreichen!« »Sicher?« »Ganz sicher! Bären haben Angst vor Treibsand!« – Hägar, Dik Browne

8 Exceptions

Fehler beim Programmieren sind unvermeidlich. Schwierigkeiten bereiten nur die unkalkulierbaren Situationen – hier ist der Umgang mit Fehlern ganz besonders heikel. Java bietet die elegante Methode der Exceptions, um mit Fehlern flexibel umzugehen.


Galileo Computing - Zum Seitenanfang

8.1 Problembereiche einzäunen Zur nächsten ÜberschriftZur vorigen Überschrift

Werden in C Routinen aufgerufen, dann haben diese keine andere Möglichkeit, als über den Rückgabewert einen Fehlschlag anzuzeigen. Der Fehlercode ist häufig –1, aber auch NULL oder 0. Allerdings kann die Null auch Korrektheit anzeigen. Irgendwie ist das willkürlich. Die Abfrage dieser Werte ist unschön und wird von uns gern unterlassen, zumal wir oft davon ausgehen, dass ein Fehler in dieser Situation gar nicht auftreten kann – diese Annahme kann eine Dummheit sein. Zudem wird der Programmfluss durch Abfragen der Rückgabeergebnisse unangenehm unterbrochen, zumal der Rückgabewert, wenn er nicht gerade einen Fehler anzeigt, weiterverwendet wird. Der Rückgabewert ist also im weitesten Sinne überladen, da er zwei Zustände anzeigt. Häufig entstehen mit den Fehlerabfragen kaskadierte if-Abfragen, die den Quellcode schwer lesbar machen.


Galileo Computing - Zum Seitenanfang

8.1.1 Exceptions in Java mit try und catch Zur nächsten ÜberschriftZur vorigen Überschrift

Bei der Verwendung von Exceptions wird der Programmfluss nicht durch Abfrage des Rückgabestatus unterbrochen. Ein besonders ausgezeichnetes Programmstück überwacht mögliche Fehler und ruft gegebenenfalls speziellen Programmcode zur Behandlung auf. Den überwachten Programmbereich (Block) leitet das Schlüsselwort try ein, und catch beendet es. Hinter catch folgt der Programmblock, der beim Auftreten eines Fehlers ausgeführt wird, um den Fehler abzufangen (daher der Ausdruck catch) oder zu behandeln. Es ist nach der Fehlerbehandlung nicht mehr so einfach möglich, an der Stelle fortzufahren, an der der Fehler auftrat. (Andere Programmiersprachen erlauben das durchaus.)


Galileo Computing - Zum Seitenanfang

8.1.2 Eine Datei mit RandomAccessFile auslesen Zur nächsten ÜberschriftZur vorigen Überschrift

Wir wollen eine Datei mit Hilfe der Klasse RandomAccessFile zeilenweise auslesen. Die Verbindung zwischen der Datei und dem zugehörigen Objekt gelingt mit dem Konstruktor, dem wir einen Dateinamen mitgeben.


Hinweis Zeilenweises Auslesen einer Datei übernimmt im Allgemeinen ein Scanner bzw. ein BufferedReader. Die Klasse RandomAccessFile ist gewählt, da sie zwei Ausnahmen anzeigt, die ein Programm behandeln muss.


Aus der API-Dokumentation geht hervor, dass der Konstruktor von RandomAccessFile eine FileNotFoundException auslösen kann. Mit Hilfe der Methode readLine() lesen wir so lange Zeilen ein, bis die Datei ausgeschöpft ist. Die Methode readLine() kann eine IOException auslösen. Wir müssen diese behandeln und setzen daher die Problemzonen in einen try- und catch-Block.

Eclipse-Icon Eine nicht behandelte Ausnahme wird von Eclipse als Fehler angezeigt.

Listing 8.1 ReadFileWithRAF.java

import java.io.*; 
 
public class ReadFileWithRAF 
{ 
  public static void main( String[] args ) 
  { 
    try 
    { 
      RandomAccessFile f; 
      f = new RandomAccessFile( "EastOfJava.txt", "r" ); 
 
      for ( String line; (line=f.readLine()) != null; ) 
        System.out.println( line ); 
    } 
    catch ( FileNotFoundException e ) 
    { 
      System.err.println( "Datei gibt’s nicht!" ); 
    } 
    catch ( IOException e ) 
    { 
      System.err.println( "Schreib-/Leseprobleme!" ); 
    } 
  } 
}

Tritt beim Laden einer Datei ein Fehler auf, wird dieser im try-Block abgefangen und im catch-Teil bearbeitet. Einem try-Block können mehrere catch-Klauseln zugeordnet sein, um verschiedene Fehlertypen aufzufangen.

Eclipse-Icon Einen try-catch-Block kann Eclipse auch selbst anlegen. Dazu wird wieder Strg + 1 bemüht, wobei Eclipse anbietet, entweder den Fehler an den Aufrufer weiterzuleiten (siehe weiter unten) oder einen try-catch-Block anzulegen.

Leere catch-Blöcke

Java schreibt vor, dass Ausnahmen in einem catch behandelt (oder nach oben geleitet) werden, aber nicht, was in catch-Blöcken zu geschehen hat. Ein leerer catch-Block ist in der Regel wenig sinnvoll, weil dann die Fehler klammheimlich unterdrückt werden. (Das wäre genauso wie ignorierte Statusrückgabewerte von C-Funktionen.) Das Mindeste ist eine minimale Fehlerausgabe via System.err.println(e) oder das informativere e.printStackTrace() für eine Exception e oder das Loggen dieser Fehler. Noch besser ist das aktive Reagieren, denn die Ausgabe selbst behandelt diesen Fehler nicht! Im catch-Block ist es durchaus legitim, wiederum andere Ausnahmen auszulösen.


Hinweis Wenn wie bei einem sleep() die InterruptedException wirklich egal ist, kann natürlich auch der Block leer sein, doch gibt es dafür nicht so viele sinnvolle Beispiele.



Galileo Computing - Zum Seitenanfang

8.1.3 Ablauf einer Ausnahmesituation Zur nächsten ÜberschriftZur vorigen Überschrift

Das Laufzeitsystem erzeugt ein Ausnahme-Objekt, wenn ein Fehler über eine Exception angezeigt werden soll. Dann wird die Abarbeitung der Programmzeilen sofort unterbrochen, und das Laufzeitsystem steuert selbstständig die erste catch-Klausel an (oder springt weiter zum Aufrufer, wie wir später sehen werden). Wenn die erste catch-Anweisung nicht zur Art des aufgetretenen Fehlers passt, werden der Reihe nach alle übrigen catch-Klauseln untersucht, und die erste übereinstimmende Klausel wird angesprungen (oder ausgewählt). Erst wird etwas versucht (daher im englischen »try«), und wenn im Fehlerfall ein Exception-Objekt im Programmstück geworfen wird, lässt es sich an einer Stelle auffangen. Da immer die erste passende catch-Klausel ausgewählt wird, darf im Beispiel die letzte catch-Klausel keinesfalls zuerst stehen, da diese auf jeden Fehler passt. Alle anderen Anweisungen in den catch-Blöcken würden dann nicht ausgeführt; der Compiler erkennt dieses Problem und gibt einen Fehler aus.


Galileo Computing - Zum Seitenanfang

8.1.4 Wiederholung abgebrochener Bereiche Zur nächsten ÜberschriftZur vorigen Überschrift

Es gibt in Java bei Ausnahmen bisher keine von der Sprache unterstützte Möglichkeit, an den Punkt zurückzukehren, der den Fehler ausgelöst hat. Das ist aber oft erwünscht, etwa, wenn eine fehlerhafte Eingabe zu wiederholen ist.

Wir werden mit JOptionPane.showInputDialog() nach einem String fragen und versuchen, diesen in eine Zahl zu konvertieren. Dabei kann natürlich etwas schiefgehen. Wenn ein Benutzer eine Zeichenkette eingibt, die keine Zahl repräsentiert, löst parseInt() eine NumberFormatException aus. Wir wollen in diesem Fall die Eingabe wiederholen.

Listing 8.2 com/tutego/insel/exceptions/ContinueInput.java, main()

int number = 0; 
while ( true ) 
{ 
  try 
  { 
    String s = javax.swing.JOptionPane.showInputDialog( 
                 "Bitte Zahl eingeben" ); 
    number = Integer.parseInt( s ); 
    break; 
  } 
  catch ( NumberFormatException ó_ò ) 
  { 
    System.err.println( "Das war keine Zahl!" ); 
  } 
} 
System.out.println( "Danke für die Zahl " + number ); 
System.exit( 0 );           // Beendet die Anwendung

Die gewählte Lösung ist einfach: Wir programmieren den gesamten Teil in einer Endlosschleife. Geht die problematische Stelle ohne Fehler durch, so beenden wir die Schleife mit break. Kommt es zu einer Ausnahme, dann wird break nicht ausgeführt, und nach der Exception gelangen wir wieder in die Endlosschleife.


Galileo Computing - Zum Seitenanfang

8.1.5 throws im Methodenkopf angeben Zur nächsten ÜberschriftZur vorigen Überschrift

Neben der rahmenbasierten Ausnahmebehandlung – dem Einzäunen von problematischen Blöcken durch einen try- und catch-Block – gibt es eine weitere Möglichkeit, auf Exceptions zu reagieren: Weiterleiten an den Aufrufer. Im Kopf der betreffenden Methode wird dazu eine throws-Klausel eingeführt. Dadurch zeigt die Methode an, dass sie eine bestimmte Exception nicht selbst behandelt, sondern diese an die aufrufende Methode weitergibt. Wird nun von der aufgerufenen Methode eine Exception ausgelöst, so wird diese Funktion abgebrochen, und der Aufrufer muss sich um den Fehler kümmern.

Dazu ein Beispiel: Eine Methode soll eine Datei öffnen und die erste Zeile auslesen. Der Dateiname wird als Argument der Methode übergeben. Da das Öffnen der Datei sowie das Lesen einer Zeile eine Ausnahme auslösen können, müssen wir diese Ausnahme behandeln. Wir fangen sie jedoch nicht in einem eigenen try- und catch-Block auf, sondern leiten sie an den Aufrufer weiter. Das bedeutet, dass er sich um den Fehler kümmern muss.

String readFirstLineFromFile( String filename ) 
  throws FileNotFoundException, IOException 
{ 
  RandomAccessFile f = new RandomAccessFile( filename, "r" ); 
  return f.readLine(); 
}

Hinweis Zwar ist die FileNotFoundException eine IOException, sodass wir hier nur IOException hätten angeben müssen, doch grundsätzlich lassen sich beliebig viele Ausnahmen durch Komma aufzählen.


Dadurch steigt der Fehler entlang der Kette von Methodenaufrufen wie eine Blase (engl. bubble) nach oben und kann irgendwann von einem Block abgefangen werden, der sich darum kümmert.

Wenn main() alles weiterleitet

Ist die Fehlerbehandlung in einem Hauptprogramm ganz egal, so können wir alle Fehler auch an die Laufzeitumgebung weiterleiten, die dann das Programm im Fehlerfall abbricht.

Listing 8.3 MirIstAllesEgal.java

import java.io.*; 
 
class MirIstAllesEgal 
{ 
  public static void main( String[] args ) throws Exception 
  { 
    RandomAccessFile f = new RandomAccessFile( "Datei.txt", "r" ); 
    System.out.println( f.readLine() ); 
  } 
}

Das funktioniert, da alle Fehler von der Klasse Exception [Genauer gesagt, sind alle Ausnahmen in Java von der Exception-Oberklasse Throwable abgeleitet.] abgeleitet sind. Wir werden das in den folgenden Abschnitten weiterverfolgen. Wird der Fehler nirgendwo sonst aufgefangen, erfolgt die Ausgabe einer Laufzeitfehlermeldung, denn das Exception-Objekt ist beim Interpreter, also bei der virtuellen Maschine, auf der äußersten Aufrufebene gelandet. Natürlich ist das kein guter Stil – obwohl es aus Gründen kürzerer Programme auch in diesem Buch so gemacht wird. Denn Fehler sollten in jedem Fall behandelt werden.

throws bei überschriebenen Methoden

Beim Überschreiben von Methoden gibt es eine wichtige Regel: Überschriebene Methoden in einer Unterklasse dürfen nicht mehr Ausnahmen auslösen, als schon beim throws-Teil der Oberklasse aufgeführt sind. Da das gegen das Substitutionsprinzip verstieße, kann eine Methode der Unterklasse nur

  • dieselben Ausnahmen wie die Oberklasse auslösen,
  • Ausnahmen spezialisieren oder
  • weglassen.

Dazu ein konstruiertes Beispiel für die beiden letzten Fälle.

Listing 8.4 ExceptionlessRandomAccessFile.java

import java.io.*; 
import java.net.ProtocolException; 
 
public class ExceptionlessRandomAccessFile extends RandomAccessFile 
{ 
  public ExceptionlessRandomAccessFile( File file, String mode ) 
           throws FileNotFoundException 
  { 
    super( file, mode ); 
  } 
 
  @Override 
  public long length() 
  { 
    try 
    { 
      return super.length(); 
    } 
    catch ( IOException e ) 
    { 
      return 0; 
    } 
  } 
 
  @Override 
  public void write( int b ) throws ProtocolException 
  { 
    try 
    { 
      super.write( b ); 
    } 
    catch ( IOException e ) 
    { 
      throw new ProtocolException(); 
    } 
  } 
}

Die Methoden length() und write() lösen in RandomAccessFile eine IOException aus. Unsere Unterklasse ExceptionlessRandomAccessFile überschreibt zunächst length() und lässt die Ausnahme in der Signatur weg. Das hat in der Nutzung einige Folgen, denn wenn wir die Klasse als ExceptionlessRandomAccessFile der Art

ExceptionlessRandomAccessFile raf = . . . 
raf.length();

verwenden, muss die nicht vorhandene zu prüfende Ausnahme von length() ebenfalls nicht abgefangen werden – und darf es auch gar nicht, weil ein try-catch auf eine IOException zu einem Compilerfehler führt. Umgekehrt: Ist raf vom Typ der Basisklasse RandomAccessFile, muss die Ausnahme auf jeden Fall gefangen werden.

RandomAccessFile raf = . . .; 
try 
{ 
  raf.length(); 
} 
catch ( IOException e ) { }

Das zeigt die Schwierigkeit bei überschriebenen Methoden, die Ausnahmen weglassen.

Bei der Methode write() führt throws den Ausnahmetyp ProtocolException als Unterklasse von IOException auf. Natürlich reicht es nicht aus, in write() einfach super.write() stehenzulassen (was nur eine allgemeinere IOException auslösen würde, aber nicht die versprochene speziellere ProtocolException). Daher fangen wir im Rumpf der Methode das super.write() ab und erzeugen die speziellere ProtocolException.


Design Wenn demnach eine überschriebene Methode der Unterklasse keine geprüften Fehler hinzufügen kann, muss das Design der Basistypen so entworfen sein, dass Unterklassen notwendige Fehler melden können.



Galileo Computing - Zum Seitenanfang

8.1.6 Abschlussbehandlung mit finally Zur nächsten ÜberschriftZur vorigen Überschrift

Nach einem (oder mehreren) catch kann optional ein finally-Block folgen. Die Laufzeitumgebung führt die Anweisungen im finally-Block immer aus, egal, ob ein Fehler auftrat oder die Anweisungen im try-catch-Block optimal durchliefen. Das heißt, der Block wird auf jeden Fall ausgeführt – lassen wir System.exit() oder Systemfehler einmal außen vor –, auch wenn im try-catch-Block ein return, break oder continue steht oder eine Anweisung eine neue Ausnahme auslöst. Der Programmcode im finally-Block bekommt auch gar nicht mit, ob vorher eine Ausnahme auftrat oder alles glattlief. [Wenn das von Interesse ist, lässt sich am Ende des try-catch-Blockes ein Flag belegen.]

Sinnvoll sind Anweisungen im finally-Block immer dann, wenn Operationen immer ausgeführt werden sollen. Eine typische Anwendung ist die Freigabe von Ressourcen oder das Schließen von Dateien.

Perfektes Schließen eines Datenstroms

In unserem Exception-Beispielprogramm ReadFileWithRAF.java haben wir eine Kleinigkeit noch nicht beachtet: das Schließen des Datenstroms.

Listing 8.5 ReadFileWithRAF.java, Ausschnitt

RandomAccessFile f; 
f = new RandomAccessFile( "EastOfJava.txt", "r" ); 
for ( String line; (line=f.readLine()) != null; ) 
  System.out.println( line );

Das Programm endet mit dem Auslesen Zeile für Zeile, aber das Schließen mit close() fehlt. Gut, nehmen wir eine Zeile hinzu:

f.close();

Das close() wiederum kann auch eine IOException auslösen, die jedoch eine schon vorhandene catch-Anweisung abfangen würde. Ist damit alles in Ordnung?

Nein, denn das Programm schließt im Fehlerfall den Datenstrom nicht! Nehmen wir an, das Öffnen führt zu keiner Ausnahme, doch beim Ablauf der Zeilen geschieht unerwartet ein Fehler, der zu einem Abbruch führt. Die JVM leitet uns in den Exception-Block, der eine Meldung gibt; aber geschlossen ist die Datei noch nicht! Wir könnten verleitet werden, in den catch-Zweig auch ein close() zu schreiben, doch ist das eine Quellcodeduplizierung, die wir vermeiden müssen.

Die optimale Lösung gibt die Ressource in einem finally frei. Da finally immer ausgeführt wird, wird die Datei freigegeben, wenn alles gut ging und ebenso im Fehlerfall.

Eine kleine Unschönheit bleibt: close() selbst muss mit einem try-catch ummantelt werden. Das führt zu etwas unschönen Konstruktionen, die TCFTC (try-catch-finally-try-catch) genannt werden.

Listing 8.6 ReadFileWithRAFFinally.java, main()

RandomAccessFile f = null; 
try 
{ 
  f = new RandomAccessFile( "EastOfJava.txt", "r" ); 
  for ( String line; (line=f.readLine()) != null; ) 
    System.out.println( line ); 
} 
catch ( FileNotFoundException e ) 
{ 
  System.err.println( "Datei gibt's nicht!" ); 
} 
catch ( IOException e ) 
{ 
  System.err.println( "Schreib-/Leseprobleme!" ); 
} 
finally 
{ 
  if ( f != null ) 
    try { f.close(); } catch ( IOException e ) { e.printStackTrace(); } 
}

Ein try ohne catch

Es kommt zu einer merkwürdigen Konstellation, wenn mit throws eine Exception nach oben geleitet wird. Dann ist ein catch für diese Fehlerart nicht notwendig. Dennoch lässt sich dann ein Block mit einer Ereignisbehandlung umrahmen, um ein finally auszuführen:

void read() throws MyException 
{ 
  try 
  { 
    // hier etwas arbeiten, was eine MyException auslösen könnte 
    return; 
  } 
  finally 
  { 
    System.out.println( "Ja, das kommt danach" ); 
  } 
}

Ausnahmen und Rückgaben verschwinden: Das Duo return und finally

Ein Phänomen in der Ausnahmebehandlung von Java ist eine return-Anweisung innerhalb eines finally-Blocks. Zunächst einmal »überschreibt« ein return im finally-Block den Rückgabewert eines return im try-catch-Block:

static String getIsbn() 
{ 
  try { 
    return "3821829877"; 
  } 
  finally { 
    return ""; 
  } 
}

Der Aufrufer empfängt immer einen leeren String.

Interessant ist auch folgendes Programm:

public static int a() 
{ 
  while ( true ) 
  { 
    try { 
      return 0; 
    } 
    finally { 
      break; 
    } 
  } 
 
  return 1; 
}

Die Ausgabe auf der Konsole ist 1. Das break im finally lässt die Laufzeitumgebung aus der Schleife austreten und den Rückgabewert ignorieren.

Ein weiteres Kuriosum sind Ausnahmen. Die Laufzeitumgebung gibt bei einer return-Anweisung im finally-Block eine im try-catch-Block ausgelöste Ausnahme nicht zum Aufrufer weiter, sondern bietet einfach die Rückgabe an. Die folgende Funktion löst zum Beispiel eine RuntimeException aus, die aber der Aufrufer der Methode nie sieht.

static void obamaVsMcCain() 
{ 
  try { 
    throw new RuntimeException(); 
  } 
  finally 
  { 
    return;       // <- Watch out for this guy 
  } 
}

Entfernen wir die Zeile mit dem return, ist das Verhalten der Laufzeitumgebung wie erwartet.

Eclipse-Icon Der Java-Compiler von Eclipse markiert die Diskrepanz und zeigt eine Warnung an (»finally block does not complete normally«). Mit der Annotation @SuppressWarnings("finally") schalten wir diesen Hinweis ab.


Galileo Computing - Zum Seitenanfang

8.1.7 Nicht erreichbare catch-Klauseln topZur vorigen Überschrift

Eine catch-Klausel heißt erreichbar, wenn es in dem try- und catch-Block eine Anweisung gibt, die die in der catch-Klausel aufgefangene Fehlerart tatsächlich auslösen kann. Zusätzlich darf vor dieser catch-Klausel natürlich kein anderes catch stehen, das diesen Fehlerfall mit abfängt. Wenn wir zum Beispiel catch(Exception e) als erstes Auffangbecken bereitstellen, werden natürlich alle Ausnahmen dort behandelt. Die Konsequenz daraus: catch-Klauseln sollten immer von den speziellen zu den allgemeinen Fehlerarten sortiert werden.

Wenn wir ein Objekt RandomAccessFile aufbauen und anschließend readLine() verwenden, so muss eine FileNotFoundException vom Konstruktor und eine IOException von readLine() abgefangen werden. Da eine FileNotFoundException eine Spezialisierung ist, also eine Unterklasse von IOException, würde ein catch(IOException e) schon reichen. Steht im Quellcode folglich der catch für die FileNotFoundException dahinter, wird der Teil nie ausgeführt werden können, und der Compiler merkt das zu Recht an.

Übertriebene throws-Klauseln

Eine Methode kompiliert, auch wenn sie zu viele oder zu allgemeine Fehlerarten in ihrer throws-Klausel angibt:

Listing 8.7 TooManyExceptions.java, openFile()

void openFile() throws FileNotFoundException, IOException, InterruptedException 
{ 
  RandomAccessFile f = new RandomAccessFile("", ""); 
}

Unsere Methode openFile() ruft den Konstruktor von RandomAccessFile auf, was bekannterweise zu einer FileNotFoundException führen kann. openFile() jedoch gibt neben FileNotFoundException noch die allgemeinere Oberklasse IOException an und meldet mit InterruptedException noch eine geprüfte Ausnahme, die der Rumpf überhaupt auslöst. Trotzdem lässt der Compiler das durch.

Beim Aufruf solcher Methoden in try-catch-Blöcken müssen in den catch-Klauseln die zu viel deklarierten Exceptions aufgefangen werden, auch wenn sie nicht wirklich erreicht werden können.

Listing 8.8 TooManyExceptions.java, useFile()

try 
{ 
  openFile(); 
} 
catch ( IOException e ) { } 
catch ( InterruptedException e ) { }

Der Sinn liegt darin, dass dies später in einer Erweiterung einer Methode, etwa einer InterruptedException, durchaus vorkommen kann, und dann sind die Aufrufer darauf schon vorbereitet.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.






<< zurück
  Zum Katalog
Zum Katalog: Java ist auch eine Insel





Java ist auch eine Insel
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Tipp
Zum Katalog: Coding for Fun





 Coding for Fun


 Buchempfehlungen
Zum Katalog: Objektorientierte Programmierung





 Objektorientierte
 Programmierung


Zum Katalog: Einstieg in Eclipse 3.4






 Einstieg in
 Eclipse 3.4


Zum Katalog: Java 6 lernen mit Eclipse






 Java 6 lernen
 mit Eclipse


Zum Katalog: NetBeans Platform 6






 NetBeans
 Platform 6


Zum Katalog: Java und XML






 Java und XML


Zum Katalog: Visual C# 2008






 Visual C# 2008


Zum Katalog: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


Zum Katalog: C++ von A bis Z






 C++ von A bis Z


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Galileo Press 2009
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