Was ist eine Exception?: Unterschied zwischen den Versionen
K |
K |
||
Zeile 4: | Zeile 4: | ||
= Was ist der Unterschied zwischen checked und unchecked Exceptions? = | = Was ist der Unterschied zwischen checked und unchecked Exceptions? = | ||
− | Unchecked Exceptions sind von der Klasse | + | Unchecked Exceptions sind von der Klasse {{JAPI|RuntimeException}} oder einer deren Unterklassen |
abgeleitet. Sie müssen nicht explizit behandelt (mit catch gefangen) oder mit throws weitergeworfen werden. | abgeleitet. Sie müssen nicht explizit behandelt (mit catch gefangen) oder mit throws weitergeworfen werden. | ||
− | Checked Exceptions sind nicht von | + | Checked Exceptions sind nicht von {{JAPI|RuntimeException}} abgeleitet. Kann eine Methode eine |
checked Exception werfen, so muss sie entweder behandelt werden (try-catch) oder die | checked Exception werfen, so muss sie entweder behandelt werden (try-catch) oder die | ||
aufrufende Methode muss sie in der throws-Klausel deklarieren. D. h. die Exception wird weiter geworfen. | aufrufende Methode muss sie in der throws-Klausel deklarieren. D. h. die Exception wird weiter geworfen. | ||
Zeile 77: | Zeile 77: | ||
Ursprünglich stimmte das, wenn man nur die vordefinierten Exception in der Java API betrachtet. Ausnahmen | Ursprünglich stimmte das, wenn man nur die vordefinierten Exception in der Java API betrachtet. Ausnahmen | ||
− | wie NullPointerException, ArrayIndexOutOfBoundsException oder IllegalArgumentException deuten wirklich | + | wie {{JAPI|NullPointerException}}, {{JAPI|ArrayIndexOutOfBoundsException}} oder {{JAPI|IllegalArgumentException}} deuten wirklich |
auf Programmierfehler hin, die in funktionierenden Programmen nie auftreten sollten. Falls doch, sollte | auf Programmierfehler hin, die in funktionierenden Programmen nie auftreten sollten. Falls doch, sollte | ||
der Bug behoben werden, statt die Exception zu behandeln. | der Bug behoben werden, statt die Exception zu behandeln. | ||
Zeile 83: | Zeile 83: | ||
Andererseits gehen Frameworks und Software-Bibliotheken mehr und mehr dazu über, nur noch unchecked Exceptions | Andererseits gehen Frameworks und Software-Bibliotheken mehr und mehr dazu über, nur noch unchecked Exceptions | ||
zu benutzen. Diese sind in der Regel nicht durch Programmierfehler bedingt. So wirft das Persistenz-Framework | zu benutzen. Diese sind in der Regel nicht durch Programmierfehler bedingt. So wirft das Persistenz-Framework | ||
− | Hibernate eine | + | Hibernate eine RuntimeException, wenn beispielsweise die Datenbank nicht verfügbar ist. |
Solche Ausnahmen können natürlich auch gefangen und behandelt werden, wenn dies möglich und sinnvoll ist. | Solche Ausnahmen können natürlich auch gefangen und behandelt werden, wenn dies möglich und sinnvoll ist. | ||
Zeile 108: | Zeile 108: | ||
eingetippt, so kann man den entsprechenden Eingabedialog erneut öffnen und den richtigen Dateinamen verlangen. | eingetippt, so kann man den entsprechenden Eingabedialog erneut öffnen und den richtigen Dateinamen verlangen. | ||
Diese Situation ist behebbar. | Diese Situation ist behebbar. | ||
− | Was soll aber passieren, wenn IOException in einem Server-Prozess fliegt, etwa, weil die Konfigurationsdatei | + | Was soll aber passieren, wenn {{JAPI|IOException}} in einem Server-Prozess fliegt, etwa, weil die Konfigurationsdatei |
der Servers nicht gelesen werden kann oder kein freier Festplattenspeicher mehr verfügbar ist. Diese | der Servers nicht gelesen werden kann oder kein freier Festplattenspeicher mehr verfügbar ist. Diese | ||
Situationen sind nicht behebbar. Es bleibt einem nichts anderes übrig, als die Exception zu loggen, ggf. den | Situationen sind nicht behebbar. Es bleibt einem nichts anderes übrig, als die Exception zu loggen, ggf. den | ||
Zeile 121: | Zeile 121: | ||
Beispiel: | Beispiel: | ||
− | Das Service-Interface von Java RMI verlangt von jeder Methode, die checked Exception RemoteException in der | + | Das Service-Interface von Java {{RMI}} verlangt von jeder Methode, die checked Exception {{JAPI|RemoteException}} in der |
throws-Klausel zu deklarieren. Dadurch wird es hart an diese Technologie gekoppelt. Soll zum Beispiel | throws-Klausel zu deklarieren. Dadurch wird es hart an diese Technologie gekoppelt. Soll zum Beispiel | ||
in Zukunft RMI durch ein anderes Remote-Procedure-Call Produkt ausgetauscht werden, sind umfangreiche | in Zukunft RMI durch ein anderes Remote-Procedure-Call Produkt ausgetauscht werden, sind umfangreiche | ||
Zeile 128: | Zeile 128: | ||
Umgekehrt ist es noch schlimmer: Besteht bereits ein Service-Interface, das im Programm verwendet wird, und | Umgekehrt ist es noch schlimmer: Besteht bereits ein Service-Interface, das im Programm verwendet wird, und | ||
soll es jetzt durch RMI implementiert werden, so muss man entsprechend throws RemoteException an allen | soll es jetzt durch RMI implementiert werden, so muss man entsprechend throws RemoteException an allen | ||
− | Methoden hinzufügen. An sämtlichen aufrufenden Stellen muss darüber hinaus die | + | Methoden hinzufügen. An sämtlichen aufrufenden Stellen muss darüber hinaus die Exception-Behandlung |
ergänzt werden. | ergänzt werden. | ||
Zeile 136: | Zeile 136: | ||
Gute Frage. Der Nutzen von checked Exceptions hat sich als sehr begrenzt heraus gestellt. Die | Gute Frage. Der Nutzen von checked Exceptions hat sich als sehr begrenzt heraus gestellt. Die | ||
Nachteile durch das (gezwungene) Behandeln (mehr Quelltext, eventuell Verschlucken der Exception, siehe oben), | Nachteile durch das (gezwungene) Behandeln (mehr Quelltext, eventuell Verschlucken der Exception, siehe oben), | ||
− | können Probleme verursachen. Es gibt einen Trend weg von checked Exceptions, z.B. werden in Hibernate | + | können Probleme verursachen. Es gibt einen Trend weg von checked Exceptions, z.B. werden in {{Hibernate}} |
− | und Spring-Framework nur noch Runtime-Exceptions verwendet. | + | und {{Spring}}-Framework nur noch Runtime-Exceptions verwendet. |
Das Konzept der checked Exceptions gibt es so nur in Java. In neueren, auch von Java inspirierten Sprachen | Das Konzept der checked Exceptions gibt es so nur in Java. In neueren, auch von Java inspirierten Sprachen | ||
wie C# oder Groovy, wurde darauf verzichtet. | wie C# oder Groovy, wurde darauf verzichtet. | ||
Zeile 148: | Zeile 148: | ||
= Was tun mit all den unbehandelten Exceptions? = | = Was tun mit all den unbehandelten Exceptions? = | ||
− | + | RuntimeExceptions die nicht mit catch gefangen und behandelt werden, nennt man uncaught Exceptions. Seit Java 1.5 | |
− | hat man die Möglichkeit, für jeden Thread einen | + | hat man die Möglichkeit, für jeden Thread einen {{JAPI|UncaughtExceptionHandler}} zu installieren. Darüber hinaus |
gibt es einen globalen [http://java.sun.com/javase/6/docs/api/java/lang/Thread.html#setDefaultUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler) Default-UncaughtExceptionHandler], der standardmäßig verwendet wird, falls kein Thread-spezifischer gesetzt wurde. | gibt es einen globalen [http://java.sun.com/javase/6/docs/api/java/lang/Thread.html#setDefaultUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler) Default-UncaughtExceptionHandler], der standardmäßig verwendet wird, falls kein Thread-spezifischer gesetzt wurde. | ||
Hier kann zentral festgelegt werden, was mit solchen Ausnahmen geschehen soll, beispielsweise die Darstellung | Hier kann zentral festgelegt werden, was mit solchen Ausnahmen geschehen soll, beispielsweise die Darstellung | ||
Zeile 159: | Zeile 159: | ||
Das ist richtig. Ursprünglich unterschied man zwischen Exceptions, die explizit vom | Das ist richtig. Ursprünglich unterschied man zwischen Exceptions, die explizit vom | ||
Programmierer erzeugt und geworfen werden und solchen, die von | Programmierer erzeugt und geworfen werden und solchen, die von | ||
− | der Java Laufzeitumgebung | + | der Java Laufzeitumgebung {{JRE}}, also der Virtuellen Maschine, implizit erzeugt werden. |
Wenn zum Beispiel versucht wird, eine Null-Referenz zu dereferenzieren oder über | Wenn zum Beispiel versucht wird, eine Null-Referenz zu dereferenzieren oder über | ||
− | die Grenzen eines Arrays hinaus zuzugreifen, wirft die Java Laufzeitumgebung automatisch | + | die Grenzen eines {{Array|Arrays}} hinaus zuzugreifen, wirft die Java Laufzeitumgebung automatisch |
eine entsprechende Exception. Daher der Name RuntimeException. | eine entsprechende Exception. Daher der Name RuntimeException. | ||
Version vom 27. Juni 2015, 14:25 Uhr
Eine Exception ist eine Ausnahmesituation, die normalerweise durch Fehler hervorgerufen wird. Diese Ausnahmen führen in der Regel zu einer Änderung des Programmablaufs, um etwa den Fehler zu beheben oder das Programm in einen sicheren Zustand zu bringen.
Inhaltsverzeichnis
- 1 Was ist der Unterschied zwischen checked und unchecked Exceptions?
- 2 Wie behandle ich eine Exception richtig?
- 3 Wann soll ich Runtime-Exceptions und wann checked Exceptions verwenden?
- 4 Stimmt es, dass RuntimeExceptions immer auf Programmierfehler hindeuten und nie gefangen werden sollten?
- 5 Was ist das Problem mit checked Exceptions?
- 6 Warum dann überhaupt checked Exceptions?
- 7 Was tun mit all den unbehandelten Exceptions?
- 8 Wieso heißt es RuntimeException? Alle Exceptions fliegen doch zur Laufzeit.
- 9 Was ist ein Error?
- 10 Was ist Throwable?
- 11 Web-Links
Was ist der Unterschied zwischen checked und unchecked Exceptions?
Unchecked Exceptions sind von der Klasse RuntimeException
oder einer deren Unterklassen
abgeleitet. Sie müssen nicht explizit behandelt (mit catch gefangen) oder mit throws weitergeworfen werden.
Checked Exceptions sind nicht von RuntimeException
abgeleitet. Kann eine Methode eine
checked Exception werfen, so muss sie entweder behandelt werden (try-catch) oder die
aufrufende Methode muss sie in der throws-Klausel deklarieren. D. h. die Exception wird weiter geworfen.
Die Begriffe Runtime-Exception und unchecked Exception können synonym verwendet werden.
<code=java>public void methodeMitRuntimeException() {
throw new NullPointerException(); // NullPointerException ist eine RuntimeException
}
public void methodeMitCheckedExceptionBehandelt() {
try { foo(); // foo() kann IOException werfen. IOException ist eine checked Exception. } catch(IOException ex) { //... Exception behandeln }
}
public void methodeMitCheckedExceptionWeiterwerfen() throws IOException {
foo(); // foo() kann IOException werfen. IOException ist eine checked Exception.
}</code=java>
Wie behandle ich eine Exception richtig?
Eine Exception sollte auf keinen Fall einfach verschluckt werden. Eine Fehlerausgabe, Logging der Exception oder ein Weiterwerfen sollten vorhanden sein. Auch ist davon abzuraten, generell alle Exceptions in einem catch abzufangen. Es sollten immer nur konkrete Ausnahmen gefangen werden. Dies verhindert, dass man "aus Versehen" eine Exception fängt, die gar nicht behandelt werden soll.
<code=java>public void foo() {
try { methodeDieExceptionsWirft(); } catch(Exception x) { // FALSCH! Nicht alle Exceptions auf einmal fangen! // FALSCH! Exceptions nicht ignorieren! }
}
public void bar() {
try { methodeDieExceptionsWirft(); } catch(FileNotFoundException fnfex) { // RICHTIG: konkrete Exceptions einzeln angeben myExceptionHandler.handleException(x); } catch(SQLException sqlex) { sqlex.printStacktrace(); // OK: Stacktrace auf Konsole ausgeben LOGGER.error(sqlex); // BESSER: Exception loggen } catch(ParseException pex) { throw new RuntimeException("unerwartete Exception", pex); // OK: checked Exception in RTEx kapseln }
}</code=java>
Wann soll ich Runtime-Exceptions und wann checked Exceptions verwenden?
Checked Exceptions zwingen den Aufrufer zur sofortigen Behandlung bzw. expliziten Weiterleitung der Exception. Dies ist nur sinnvoll, wenn eine Chance besteht, die Ausnahmesituation zu reparieren ("reasonably be expected to recover" [1]). Andernfalls gibt es nur die Möglichkeit, dem Anwender eine Fehlermeldung zu präsentieren, die Exception zu loggen oder die Anwendung kontrolliert zu beenden. In solchen Fällen sind ungeprüfte Ausnahmen (Runtime-Exceptions) vorzuziehen.
Unchecked Exceptions — The Controversy (The Java™ Tutorials > Essential Classes > Exceptions)
Stimmt es, dass RuntimeExceptions immer auf Programmierfehler hindeuten und nie gefangen werden sollten?
Ursprünglich stimmte das, wenn man nur die vordefinierten Exception in der Java API betrachtet. Ausnahmen
wie NullPointerException
, ArrayIndexOutOfBoundsException
oder IllegalArgumentException
deuten wirklich
auf Programmierfehler hin, die in funktionierenden Programmen nie auftreten sollten. Falls doch, sollte
der Bug behoben werden, statt die Exception zu behandeln.
Andererseits gehen Frameworks und Software-Bibliotheken mehr und mehr dazu über, nur noch unchecked Exceptions zu benutzen. Diese sind in der Regel nicht durch Programmierfehler bedingt. So wirft das Persistenz-Framework Hibernate eine RuntimeException, wenn beispielsweise die Datenbank nicht verfügbar ist. Solche Ausnahmen können natürlich auch gefangen und behandelt werden, wenn dies möglich und sinnvoll ist.
Eine Gleichsetzung Runtime-Exceptions == Programmierfehler kann also nicht verallgemeinert werden.
Was ist das Problem mit checked Exceptions?
Checked Exceptions sind nur dann sinnvoll, wenn bei ihrem Auftreten unmittelbar die Möglichkeit besteht, die Ausnahmesituation zu beheben und dem Programmablauf normal fortzufahren.
- Checked Exceptions führen zu überflüssigem Code
In der Praxis sind Fälle, in denen man auf jeden Fall von einer Behebbarkeit ausgehen kann, jedoch sehr selten. Trotzdem wird er Entwickler gezwungen, die Exception (unnötigerweise) zu behandeln, da sonst der Code nicht kompilierbar ist. Da führt zu eigentlich überflüssigen try-catch-Anweisungen, die den Quelltext länger und schwerer zu lesen machen. Im schlimmsten Fall wird die Exception einfach nur verschluckt.
- Behebbare Ausnahmen sind selten und oft nicht eindeutig zu identifizieren
Beispiel:
IOException auf der Java Standard-API ist eine checked Exception, sie muss also behandelt werden. In einigen
Anwendungsfällen ist dies natürlich möglich. Hat der Anwender beispielsweise einen falschen Dateinamen
eingetippt, so kann man den entsprechenden Eingabedialog erneut öffnen und den richtigen Dateinamen verlangen.
Diese Situation ist behebbar.
Was soll aber passieren, wenn IOException
in einem Server-Prozess fliegt, etwa, weil die Konfigurationsdatei
der Servers nicht gelesen werden kann oder kein freier Festplattenspeicher mehr verfügbar ist. Diese
Situationen sind nicht behebbar. Es bleibt einem nichts anderes übrig, als die Exception zu loggen, ggf. den
Administrator zu verständigen und das Programm zu beenden.
IOException kann also nicht immer sinnvoll behandelt werden. Daraus folgt, dass sie eigentlich keine checked Exception
sein sollte, sondern eine Runtime-Exception.
Generell sollten Frameworks oder allgemein verwendbare Bibliotheken keine checked Exceptions verwenden. In abgeschlossenen Software-Systemen (Individualsoftware) können geprüfte Ausnahmen manchmal sinnvoll sein.
- Checked Exceptions verschmutzen Interfaces und führen zu hoher Kopplung
Beispiel:
Das Service-Interface von Java Vorlage:RMI verlangt von jeder Methode, die checked Exception RemoteException
in der
throws-Klausel zu deklarieren. Dadurch wird es hart an diese Technologie gekoppelt. Soll zum Beispiel
in Zukunft RMI durch ein anderes Remote-Procedure-Call Produkt ausgetauscht werden, sind umfangreiche
Änderungen am Quelltext notwendig, um überall die RemoteExceptions und die entsprechenden catch-Blöcke
zu entfernen.
Umgekehrt ist es noch schlimmer: Besteht bereits ein Service-Interface, das im Programm verwendet wird, und
soll es jetzt durch RMI implementiert werden, so muss man entsprechend throws RemoteException an allen
Methoden hinzufügen. An sämtlichen aufrufenden Stellen muss darüber hinaus die Exception-Behandlung
ergänzt werden.
Warum dann überhaupt checked Exceptions?
Gute Frage. Der Nutzen von checked Exceptions hat sich als sehr begrenzt heraus gestellt. Die Nachteile durch das (gezwungene) Behandeln (mehr Quelltext, eventuell Verschlucken der Exception, siehe oben), können Probleme verursachen. Es gibt einen Trend weg von checked Exceptions, z.B. werden in Vorlage:Hibernate und Vorlage:Spring-Framework nur noch Runtime-Exceptions verwendet. Das Konzept der checked Exceptions gibt es so nur in Java. In neueren, auch von Java inspirierten Sprachen wie C# oder Groovy, wurde darauf verzichtet.
JavaSpecialists 033 - Making Exceptions Unchecked <br\> Java's checked exceptions were a mistake (and here's what I would like to do about it)<br\> Bruce Eckel's MindView, Inc: Does Java need Checked Exceptions?<br\>
Was tun mit all den unbehandelten Exceptions?
RuntimeExceptions die nicht mit catch gefangen und behandelt werden, nennt man uncaught Exceptions. Seit Java 1.5
hat man die Möglichkeit, für jeden Thread einen UncaughtExceptionHandler
zu installieren. Darüber hinaus
gibt es einen globalen Default-UncaughtExceptionHandler, der standardmäßig verwendet wird, falls kein Thread-spezifischer gesetzt wurde.
Hier kann zentral festgelegt werden, was mit solchen Ausnahmen geschehen soll, beispielsweise die Darstellung
eines Fehlerdialogs.
Wieso heißt es RuntimeException? Alle Exceptions fliegen doch zur Laufzeit.
Das ist richtig. Ursprünglich unterschied man zwischen Exceptions, die explizit vom Programmierer erzeugt und geworfen werden und solchen, die von der Java Laufzeitumgebung Vorlage:JRE, also der Virtuellen Maschine, implizit erzeugt werden. Wenn zum Beispiel versucht wird, eine Null-Referenz zu dereferenzieren oder über die Grenzen eines Vorlage:Array hinaus zuzugreifen, wirft die Java Laufzeitumgebung automatisch eine entsprechende Exception. Daher der Name RuntimeException.
Rein praktisch können RuntimeException natürlich auch explizit vom Programmierer erzeugt und geworfen werden, ganz genau wie geprüfte Ausnahmen.
Was ist ein Error?
Ein Error ist auch eine Art Exception, die eine schwere Ausnahmesituation darstellt. Sie kann in der Regel nicht behoben werden (z.B. OutOfMemoryError). Ähnlich wie RuntimeExceptions müssen Errors weder gefangen noch mit der throws-Klausel deklariert werden.
Was ist Throwable?
Throwable ist die Oberklasse für alle Exceptions, RuntimeExceptions und Errors - also alles, was geworfen werden kann.
Web-Links
--tfa 13:08, 30. Juli 2010 (CET)