Was ist eine Exception?: Unterschied zwischen den Versionen
K (→Was ist der Unterschied zwischen checked und unchecked Exceptions?) |
K (→Was ist der Unterschied zwischen checked und unchecked Exceptions?) |
||
(4 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
Zeile 31: | Zeile 31: | ||
foo(); // foo() kann IOException werfen. IOException ist eine checked Exception. | foo(); // foo() kann IOException werfen. IOException ist eine checked Exception. | ||
}</syntaxhighlight> | }</syntaxhighlight> | ||
+ | |||
+ | Mehr zur [[NullPointerException]]... | ||
= Wie behandle ich eine Exception richtig? = | = Wie behandle ich eine Exception richtig? = | ||
Zeile 38: | Zeile 40: | ||
Dies verhindert, dass man "aus Versehen" eine Exception fängt, die gar nicht behandelt werden soll. | Dies verhindert, dass man "aus Versehen" eine Exception fängt, die gar nicht behandelt werden soll. | ||
− | < | + | <syntaxhighlight lang="java">public void foo() { |
try { | try { | ||
methodeDieExceptionsWirft(); | methodeDieExceptionsWirft(); | ||
Zeile 61: | Zeile 63: | ||
throw new RuntimeException("unerwartete Exception", pex); // OK: checked Exception in RTEx kapseln | throw new RuntimeException("unerwartete Exception", pex); // OK: checked Exception in RTEx kapseln | ||
} | } | ||
− | }</ | + | }</syntaxhighlight> |
− | |||
= Wann soll ich Runtime-Exceptions und wann checked Exceptions verwenden? = | = Wann soll ich Runtime-Exceptions und wann checked Exceptions verwenden? = | ||
Zeile 186: | Zeile 187: | ||
--[[Benutzer:tfa|tfa]] 13:08, 30. Juli 2010 (CET) | --[[Benutzer:tfa|tfa]] 13:08, 30. Juli 2010 (CET) | ||
− | |||
[[Kategorie:Java Grundlagen]] | [[Kategorie:Java Grundlagen]] |
Aktuelle Version vom 19. Dezember 2018, 16:55 Uhr
Dieser Artikel überschneidet sich inhaltlich teilweise mit Exception (Java)
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 Fragen
- 12 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.
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.
}
Mehr zur NullPointerException...
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.
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
}
}
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 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 Hibernate 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 wie C# oder Groovy, wurde darauf verzichtet.
- JavaSpecialists 033 - Making Exceptions Unchecked
- Java's checked exceptions were a mistake (and here's what I would like to do about it)
- Bruce Eckel's MindView, Inc: Does Java need Checked 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 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 JRE, also der Virtuellen Maschine, implizit erzeugt werden. Wenn zum Beispiel versucht wird, eine Null-Referenz zu dereferenzieren oder über die Grenzen eines Arrays 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.
Fragen
Das Thema wurde nicht ausreichend behandelt? Du hast Fragen dazu und brauchst weitere Informationen? Lass Dir von uns helfen!
- Besuche uns im Byte-Welt-Forum
- Besuche unseren Chat
Wir helfen dir gerne!
Dir hat dieser Artikel gefallen? Oder Du hast Fehler entdeckt und möchtest zur Berichtigung beitragen? Prima! Schreibe einen Kommentar!
Du musst angemeldet sein, um einen Kommentar abzugeben.
Web-Links
--tfa 13:08, 30. Juli 2010 (CET)