Advanced Java Services | throws throw |
Statt try-catch zu verwenden kann man auch versuchen, die Ausnahme weiterzuwerfen. Dies geschieht mit dem Schlüsselwort throws. Dann wird sozusagen die nächsthöhere Instanz damit beauftragt, die Ausnahme zu behandeln (oder wieder weiterzuwerfen). In der Regel steht die kritische Anweisung in einem Konstrukor oder in einer Methode. Will man keine try-catch-Behandlung, so kann man die Signatur einer Methode um eine sogenannte throws-Klausel ergänzen. Wir betrachten das folgende Beispiel.
import java.io.*; public class ThrowsDemo { public static void main(String args[]) { ThrowsDemo td = new ThrowsDemo(); td.openFile(); // unreported exception IOException // must be caught or declared to be thrown } public void openFile(String datei) throws IOException { FileReader fr = new FileReader(datei); // ... } } // end class
Anstatt in der Methode openFile() die Ausnahme abzufangen werfen wir Sie mit einer throws-Klausel weiter. Jetzt muß der Aufrufer der Methode die Exception behandeln. Entweder er setzt try-catch ein oder er wirft die Ausnahme wieder weiter. Dann muß die Methode, in der das kritische Statement steht mit einer entsprechenden throws-Klausel versehen werden. Hier müßte man dann die main-Methode mit einer entsprechenden throws-Klausel versehen.
import java.io.*; public class ThrowsDemo { public static void main(String args[]) throws IOException { ThrowsDemo td = new ThrowsDemo(); td.openFile(); } public void openFile(String datei) throws IOException { FileReader fr = new FileReader(datei); // ... } } // end class
Eine Ausnahme solange nach oben zu werfen bis man schließlich die Signatur von main ergänzt ist zwar
zulässig, hat aber mit echter Ausnahmebehandlung nichts mehr zu tun, denn der ClassLoader, der die
main-Klasse lädt, macht natürlich keine Ausnahmebehandlung. Tritt die Ausnahmesituation ein, wird das
Programm sofort beendet. Für eine echte Ausnahmebehandlung braucht man also spätestens in main ein
try-catch.
Einige Beispiele für Methoden bzw. Konstruktoren aus der Klassenbibliothek, deren Signaturen
um eine throws-Klausel ergänzt sind.
public static int parseInt(String s) throws NumberFormatException { return parseInt(s,10); }
public FileReader(String fileName) throws FileNotFoundException { super(new FileInputStream(fileName)); }
private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { //... }
Das letzte Beispiel zeigt, daß man auch mehrere Ausnahmen werfen kann, man trennt sie einfach durch ein Komma.
Bleibt noch das Schlüsselwort throw. Mit throw kann man selbst Ausnahmen auslösen. Dazu muß man zuerst ein Ausnahmeobjekt erzeugen und es dann mit throw werfen. Das folgende Beispiel zeigt den Anfang des Quellcodes der Methode parseInt aus der Klasse Integer
public static int parseInt(String s, int radix) throws NumberFormatException { if (s == null) { throw new NumberFormatException("null"); } if (radix < Character.MIN_RADIX) { throw new NumberFormatException ("radix " + radix + " less than Character.MIN_RADIX"); } if (radix > Character.MAX_RADIX) { throw new NumberFormatException ("radix " + radix + " greater than Character.MAX_RADIX"); } // ... }
Hier wird zunächst überprüft, ob beim Aufruf der Methode halbwegs vernünftige Parameter übergeben wurden. Ist dies nicht der Fall, wird das eigentliche parsen garnicht begonnen. das ist eine typische Programmsituation. Erst wenn man sicher ist, daß die Eingabeparameter gewisse Mindestanforderungen erfüllen, beginnt man mit der eigentlichen Arbeit. Wie man sieht, reicht ein Konstruktoraufruf alleine nicht aus, das Objekt muß explizit geworfen werden und man braucht für jedes Objekt ein eigenes throw. Wirft man eine checked exception, so muß man diese mit throws in der Signatur der umhüllenden Methode angeben (man könnte sie theoretisch mit try-catch abfangen, aber das macht in dieser Situation keinen Sinn). Wirft man dagegen eine unchecked exception, so braucht man die Signatur der Methode nicht ergänzen, man kann es aber der Deutlichkeit halber tun. Die folgende Methode wirft drei Ausnahmen. Nur InterruptedException muß mit throws in der Signatur ergänzt werden.
public void throwing(int a) throws InterruptedException { if (a==0) throw new NullPointerException(); // unchecked exception if (a==1) throw new IndexOutOfBoundsException(); // unchecked exception if(a==2) throw new InterruptedException(); // checked exception }