Grundlegendes zu aktivierten und nicht aktivierten Ausnahmen in Java


703

Joshua Bloch in " Effective Java " sagte das

Verwenden Sie geprüfte Ausnahmen für wiederherstellbare Bedingungen und Laufzeitausnahmen für Programmierfehler (Punkt 58 in der 2. Ausgabe).

Mal sehen, ob ich das richtig verstehe.

Hier ist mein Verständnis einer überprüften Ausnahme:

try{
    String userInput = //read in user input
    Long id = Long.parseLong(userInput);
}catch(NumberFormatException e){
    id = 0; //recover the situation by setting the id to 0
}

1. Wird das oben Gesagte als geprüfte Ausnahme angesehen?

2. Ist RuntimeException eine nicht aktivierte Ausnahme?

Hier ist mein Verständnis einer ungeprüften Ausnahme:

try{
    File file = new File("my/file/path");
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){

//3. What should I do here?
    //Should I "throw new FileNotFoundException("File not found");"?
    //Should I log?
    //Or should I System.exit(0);?
}

4. Könnte der obige Code nicht auch eine geprüfte Ausnahme sein? Kann ich versuchen, die Situation so wiederherzustellen? Kann ich? (Hinweis: Meine dritte Frage befindet sich catchoben)

try{
    String filePath = //read in from user input file path
    File file = new File(filePath);
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){
    //Kindly prompt the user an error message
    //Somehow ask the user to re-enter the file path.
}

5. Warum machen die Leute das?

public void someMethod throws Exception{

}

Warum lassen sie die Ausnahme aufblasen? Ist es nicht besser, den Fehler früher zu behandeln? Warum sprudeln?

6. Soll ich die genaue Ausnahme in die Luft sprudeln lassen oder sie mit Ausnahme maskieren?

Unten sind meine Lesungen

Wann sollte ich in Java eine aktivierte Ausnahme erstellen und wann sollte es sich um eine Laufzeitausnahme handeln?

Wann werden aktivierte und nicht aktivierte Ausnahmen ausgewählt?


6
Ich habe ein großartiges Beispiel für eine ungeprüfte Ausnahme. Ich habe eine DataSeriesKlasse, die Daten enthält, die immer in zeitbasierter Reihenfolge bleiben müssen. Es gibt eine Methode, um DataPointam Ende von a eine neue hinzuzufügen DataSeries. Wenn mein gesamter Code während des gesamten Projekts ordnungsgemäß funktioniert, DataPointsollte am Ende niemals ein Code hinzugefügt werden, der ein vorheriges Datum zu dem bereits am Ende hat. Jedes Modul im gesamten Projekt wird mit dieser Binsenweisheit erstellt. Ich überprüfe diese Bedingung jedoch und löse eine ungeprüfte Ausnahme, wenn dies passiert. Warum? Wenn es passiert, möchte ich wissen, wer dies tut und es beheben.
Erick Robertson

3
Um noch mehr Verwirrung zu stiften. Viele Leute haben vor ~ 10 Jahren geprüfte Ausnahmen befürwortet, aber die Ansicht bewegt sich heutzutage immer mehr in Richtung "geprüfte Ausnahmen sind schlecht". (
Kaj

10
Es ist nur dann nützlich, eine Ausnahme zu behandeln, wenn Sie etwas Nützliches damit zu tun haben. Andernfalls sollten Sie den Anrufer damit umgehen lassen. Es ist normalerweise nicht sinnvoll, es zu protokollieren und so zu tun, als wäre es nicht geschehen. Nur neu zu werfen ist sinnlos. Das Einschließen einer RuntimeException ist nicht so nützlich wie manche denken, sondern lässt den Compiler nur aufhören, Ihnen zu helfen. (IMHO)
Peter Lawrey

40
Wir sollten aufhören, die umfassend irreführenden Begriffe der geprüften / ungeprüften Ausnahmen zu verwenden. Sie sollten genannt werden Check-mandatierten vs Check-nicht-mandatierten Ausnahmen.
Seliger Geek

3
Ich habe auch über den 5. Punkt nachgedacht. Public void method_name löst eine Ausnahme aus {} Warum machen manche Leute das?
Maveň

Antworten:


474

Viele Leute sagen, dass geprüfte Ausnahmen (dh diese, die Sie explizit abfangen oder neu werfen sollten) überhaupt nicht verwendet werden sollten. Sie wurden beispielsweise in C # entfernt, und die meisten Sprachen haben sie nicht. Sie können also immer eine Unterklasse von RuntimeException(nicht aktivierte Ausnahme) auslösen.

Ich denke jedoch, dass geprüfte Ausnahmen nützlich sind - sie werden verwendet, wenn Sie den Benutzer Ihrer API dazu zwingen möchten, darüber nachzudenken, wie mit der Ausnahmesituation umgegangen werden soll (wenn sie wiederherstellbar ist). Es ist nur so, dass geprüfte Ausnahmen in der Java-Plattform überbeansprucht werden, was dazu führt, dass die Leute sie hassen.

Hier ist meine erweiterte Sicht auf das Thema .

Zu den besonderen Fragen:

  1. Ist das NumberFormatExceptioneine geprüfte Ausnahme?
    Nr. NumberFormatExceptionIst deaktiviert (= ist Unterklasse von RuntimeException). Warum? Ich weiß es nicht. (aber es hätte eine Methode geben sollen isValidInteger(..))

  2. Ist RuntimeExceptioneine ungeprüfte Ausnahme?
    Ja genau.

  3. Was soll ich hier machen?
    Es hängt davon ab, wo sich dieser Code befindet und was passieren soll. Wenn es sich in der UI-Ebene befindet, fangen Sie es ab und zeigen Sie eine Warnung an. Wenn es in der Service-Schicht ist - fangen Sie es überhaupt nicht - lassen Sie es sprudeln. Schluck die Ausnahme einfach nicht. Wenn in den meisten Fällen eine Ausnahme auftritt, sollten Sie eine der folgenden Optionen auswählen:

    • logge es ein und kehre zurück
    • wirf es erneut (erkläre es als von der Methode geworfen)
    • Erstellen Sie eine neue Ausnahme, indem Sie die aktuelle Ausnahme im Konstruktor übergeben
  4. Könnte der obige Code nicht auch eine geprüfte Ausnahme sein? Kann ich versuchen, die Situation so wiederherzustellen? Kann ich?
    Es hätte sein können. Aber nichts hindert Sie daran, auch die ungeprüfte Ausnahme abzufangen

  5. Warum fügen Leute Klasse Exceptionin die Throws-Klausel ein?
    Meistens, weil die Leute faul sind, darüber nachzudenken, was sie fangen und was sie neu werfen sollen. Werfen Exceptionist eine schlechte Praxis und sollte vermieden werden.

Leider gibt es keine einzige Regel, mit der Sie bestimmen können, wann zu fangen, wann neu zu werfen, wann aktiviert und wann nicht aktivierte Ausnahmen zu verwenden sind. Ich bin damit einverstanden, dass dies viel Verwirrung und viel schlechten Code verursacht. Das allgemeine Prinzip wird von Bloch angegeben (Sie haben einen Teil davon zitiert). Und das allgemeine Prinzip besteht darin, eine Ausnahme auf die Ebene zu werfen, auf der Sie damit umgehen können.


36
In Bezug auf das Auslösen von Ausnahmen ist es nicht immer so, dass die Leute faul sind. Es ist auch üblich, dass Sie beim Implementieren von Frameworks Benutzern des Frameworks erlauben, Ausnahmen auszulösen. Sie können zB die Signatur der Callable-Schnittstelle in JSE
Kaj

10
@Kaj - ja, solche allgemeinen Dinge wie Callable, Interceptors und dergleichen sind Sonderfälle. Aber in den meisten Fällen ist es, weil die Leute faul sind :)
Bozho

7
re: 3.1 "log it and return" Tun Sie dies mit Bedacht. Dies ist sehr nah am Essen oder Verstecken und Ausnahme. Ich würde dies für etwas tun, das kein Problem anzeigt, das nicht wirklich außergewöhnlich ist. Protokolle werden überflutet und zu leicht ignoriert.
Chris

4
"Wenn Sie den Benutzer Ihrer API dazu zwingen möchten, über den Umgang mit der Ausnahmesituation nachzudenken" - Sie können niemanden zum Nachdenken zwingen, wenn er dies nicht möchte. Wenn sie nicht denken möchten, schreiben sie einen schlechten Ausnahmeblock, der überhaupt nichts tut oder, schlimmer noch, kritische Fehlerinformationen löscht oder stört. Deshalb sind geprüfte Ausnahmen ein Fehler.
Adrianos

3
@adrianos "... du kannst niemanden zum Nachdenken zwingen, wenn er nicht will ..." Mit dieser Denkweise könnten wir auch Kompilierungsfehler beseitigen ... Ich ziele nicht wirklich auf dich, ich habe das gehört Argument immer wieder und finden es immer noch die schlechteste Erklärung für die Kennzeichnung von Checked Exceptions als Fehler. Als Randnotiz habe ich zuvor eine solche Sprache gesehen, in der Kompilieren (und tatsächlich auch Laufzeitfehler) durch Desing effektiv unmöglich gemacht wurden. Diese Straße führte zu einigen sehr dunklen Orten.
Newtopian

233

Ob etwas eine "geprüfte Ausnahme" ist, hat nichts damit zu tun, ob Sie es abfangen oder was Sie im catch-Block tun. Es ist eine Eigenschaft von Ausnahmeklassen. Alles, was eine Unterklasse mit Exception Ausnahme von RuntimeExceptionund seine Unterklassen ist, ist eine geprüfte Ausnahme.

Der Java-Compiler zwingt Sie, entweder geprüfte Ausnahmen abzufangen oder sie in der Methodensignatur zu deklarieren. Es sollte die Sicherheit des Programms verbessern, aber die Mehrheit scheint der Meinung zu sein, dass es die damit verbundenen Designprobleme nicht wert ist.

Warum lassen sie die Ausnahme aufblasen? Ist es nicht besser, Fehler zu behandeln, je früher, desto besser? Warum sprudeln?

Denn das ist der ganze Punkt der Ausnahmen. Ohne diese Möglichkeit würden Sie keine Ausnahmen benötigen. Sie ermöglichen es Ihnen, Fehler auf einer von Ihnen gewählten Ebene zu behandeln, anstatt Sie zu zwingen, sie in Methoden auf niedriger Ebene zu behandeln, in denen sie ursprünglich auftreten.


3
Vielen Dank! Ich werfe gelegentlich Ausnahmen aus meinen Methoden wegen des Crap-in-Crape-Out-Prinzips. Ich, einer der Entwickler in meinem Team, möchte einen ungültigen xpath-Ausdruck eingeben. Es liegt an ihnen, die Ausnahme zu behandeln. In dem unwahrscheinlichen Fall, dass sie eine Ausnahme abfangen und nichts tun, werden sie bei der Codeüberprüfung davon erfahren.
Jeremyjjbrown

12
"Alles, was eine Unterklasse von Throwable ist, mit Ausnahme von RuntimeException und seinen Unterklassen, ist eine geprüfte Ausnahme." - Ihre Aussage ist falsch. Der Fehler erbt auch Throwable und ist deaktiviert.
Bartzilla

8
@JonasEicher: Grundsätzlich besteht ein Hauptvorteil von Ausnahmen darin, dass Sie auswählen können, wo im Aufrufstapel Fehler behandelt werden sollen, was häufig recht hoch ist, während die dazwischen liegenden Ebenen völlig frei von Artefakten bei der Fehlerbehandlung bleiben. Überprüfte Ausnahmen zerstören genau diesen Vorteil. Ein weiteres Problem besteht darin, dass die aktivierte / deaktivierte Unterscheidung an die Ausnahmeklasse gebunden ist, die auch eine konzeptionelle Kategorisierung von Ausnahmen darstellt - wobei zwei Aspekte gemischt werden, die nicht unbedingt miteinander zusammenhängen.
Michael Borgwardt

2
"Aber die Mehrheitsmeinung scheint zu sein, dass es die damit verbundenen Designprobleme nicht wert ist." - Zitat bitte?
Kervin

3
@Bartzilla Ja. Der Vollständigkeit Throwablehalber , wie der Javadoc für sagt: "Throwable und jede Unterklasse von Throwable, die nicht auch eine Unterklasse von RuntimeException oder Error ist, gelten als geprüfte Ausnahmen"
Bart van Heukelom

74
  1. Wird das oben Gesagte als geprüfte Ausnahme angesehen? Nein Die Tatsache , dass Sie eine Ausnahme sind Handling macht es nicht ein , Checked Exceptionwenn es ein RuntimeException.

  2. Ist RuntimeExceptionein unchecked exception? Ja

Checked Exceptionssind subclassesvon java.lang.Exception Unchecked Exceptionssind subclassesvonjava.lang.RuntimeException

Aufrufe, die geprüfte Ausnahmen auslösen, müssen in einem try {} -Block eingeschlossen oder in einer höheren Ebene im Aufrufer der Methode behandelt werden. In diesem Fall muss die aktuelle Methode deklarieren, dass diese Ausnahmen ausgelöst werden, damit die Aufrufer geeignete Vorkehrungen treffen können, um die Ausnahme zu behandeln.

Hoffe das hilft.

F: Soll ich die genaue Ausnahme in die Luft sprudeln lassen oder sie mit Ausnahme maskieren?

A: Ja, dies ist eine sehr gute Frage und eine wichtige Überlegung zum Design. Die Klasse Exception ist eine sehr allgemeine Ausnahmeklasse und kann zum Umschließen interner Ausnahmen auf niedriger Ebene verwendet werden. Sie sollten eine benutzerdefinierte Ausnahme erstellen und in diese einschließen. Aber, und eine große - Niemals in der zugrunde liegenden ursprünglichen Grundursache dunkel. Gehen Sie zum Beispiel Don't everwie folgt vor:

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException("Cannot login!!"); //<-- Eat away original root cause, thus obscuring underlying problem.
}

Gehen Sie stattdessen wie folgt vor:

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException(sqle); //<-- Wrap original exception to pass on root cause upstairs!.
}

Das Wegfressen der ursprünglichen Grundursache ist ein Albtraum für Produktionsunterstützungsteams, auf die sie nur Zugriff auf Anwendungsprotokolle und Fehlermeldungen erhalten. Letzteres ist zwar ein besseres Design, aber viele Leute verwenden es nicht oft, weil Entwickler die zugrunde liegende Nachricht einfach nicht an den Anrufer weitergeben. Machen Sie sich also eine feste Notiz: Geben Sie Always pass on the actual exceptionzurück, ob eine anwendungsspezifische Ausnahme vorliegt oder nicht.

Beim Versuch zu fangen RuntimeExceptions

RuntimeExceptions sollten in der Regel nicht versucht werden. Sie signalisieren in der Regel einen Programmierfehler und sollten in Ruhe gelassen werden. Stattdessen sollte der Programmierer die Fehlerbedingung überprüfen, bevor er Code aufruft, der zu a führen kann RuntimeException. Zum Beispiel:

try {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welcome to my site!);
} catch (NullPointerException npe) {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Dies ist eine schlechte Programmierpraxis. Stattdessen hätte eine Nullprüfung wie folgt durchgeführt werden sollen:

if (userObject != null) {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
} else {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

Aber es gibt Zeiten, in denen eine solche Fehlerprüfung teuer ist, wie z. B. die Formatierung von Zahlen.

try {
    String userAge = (String)request.getParameter("age");
    userObject.setAge(Integer.parseInt(strUserAge));
} catch (NumberFormatException npe) {
   sendError("Sorry, Age is supposed to be an Integer. Please try again.");
}

Hier lohnt sich die Fehlerprüfung vor dem Aufruf nicht, da im Wesentlichen der gesamte Konvertierungscode von Zeichenfolge in Ganzzahl innerhalb der parseInt () -Methode dupliziert wird - und ist fehleranfällig, wenn sie von einem Entwickler implementiert wird. Es ist also besser, Try-Catch einfach wegzulassen.

Also NullPointerExceptionund NumberFormatExceptionbeides RuntimeExceptions, das Abfangen von a NullPointerExceptionsollte durch eine ordnungsgemäße Nullprüfung ersetzt werden, während ich empfehle, ein NumberFormatExceptionexplizit abzufangen, um eine mögliche Einführung von fehleranfälligem Code zu vermeiden.


Vielen Dank. Noch eine Frage, wenn Sie die sprudeln exception, sollte ich die genaue Ausnahme sprudeln oder sie mit maskieren Exception. Ich schreibe Code über einen alten Code und werde Exceptionüberall in die Luft gesprudelt. Ich frage mich, ob dies das richtige Verhalten ist.
Thang Pham

1
Dies ist eine sehr gute und wichtige Frage, die meine Antwort so bearbeitet hat, dass sie die Erklärung enthält.
D-Live

Vielen Dank. Könnten Sie mir den Inhalt von zeigen LoginFailureException(sqle)?
Thang Pham

1
Ich habe keinen Code für dieses Zeug, ich habe nur die Namen usw. erfunden. Wenn Sie java.lang.Exception sehen, hat es 4 Konstruktoren, von denen zwei java.lang.Throwable akzeptieren. In den obigen Ausschnitten habe ich angenommen, dass ein Konstruktor LoginFailureExceptionerweitert Exceptionund deklariert wirdpublic LoginFailureException(Throwable cause) { super(cause) }
d-live

Beste Antwort zum Thema. Ich denke, Laufzeitausnahmen sollten nicht abgefangen werden, da diese Ausnahmen aufgrund des Mangels an guter Programmierung auftreten. Ich bin völlig einverstanden mit dem Teil "Das Wegfressen der ursprünglichen Grundursache begräbt die eigentliche Ursache jenseits der Wiederherstellung ist ein Albtraum für Produktionsunterstützungsteams, auf die sie nur Zugriff auf Anwendungsprotokolle und Fehlermeldungen erhalten."
Huseyin

19

1. Wenn Sie sich bei einer Ausnahme nicht sicher sind, überprüfen Sie die API:

 java.lang.Object
 extended by java.lang.Throwable
  extended by java.lang.Exception
   extended by java.lang.RuntimeException  //<-NumberFormatException is a RuntimeException  
    extended by java.lang.IllegalArgumentException
     extended by java.lang.NumberFormatException

2. Ja, und jede Ausnahme, die es erweitert.

3 . Es ist nicht erforderlich, dieselbe Ausnahme zu fangen und zu werfen. In diesem Fall können Sie einen neuen Dateidialog anzeigen.

4. FileNotFoundException ist bereits eine aktivierte Ausnahme.

5. Wenn erwartet wird, dass die Methode aufruft someMethod, um die Ausnahme abzufangen, kann letztere ausgelöst werden. Es "geht nur den Ball". Ein Beispiel für die Verwendung wäre, wenn Sie es in Ihre eigenen privaten Methoden werfen und stattdessen die Ausnahme in Ihrer öffentlichen Methode behandeln möchten.

Eine gute Lektüre ist das Oracle-Dokument selbst: http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

Warum haben die Designer beschlossen, eine Methode zu erzwingen, um alle nicht erfassten geprüften Ausnahmen anzugeben, die innerhalb ihres Geltungsbereichs ausgelöst werden können? Jede Ausnahme, die von einer Methode ausgelöst werden kann, ist Teil der öffentlichen Programmierschnittstelle der Methode. Diejenigen, die eine Methode aufrufen, müssen die Ausnahmen kennen, die eine Methode auslösen kann, damit sie entscheiden können, was mit ihnen geschehen soll. Diese Ausnahmen sind ebenso Teil der Programmierschnittstelle dieser Methode wie ihre Parameter und ihr Rückgabewert.

Die nächste Frage könnte lauten: "Wenn es so gut ist, die API einer Methode zu dokumentieren, einschließlich der Ausnahmen, die sie auslösen kann, warum nicht auch Laufzeitausnahmen angeben?" Laufzeitausnahmen stellen Probleme dar, die das Ergebnis eines Programmierproblems sind, und daher kann nicht erwartet werden, dass der API-Clientcode von ihnen wiederhergestellt oder in irgendeiner Weise behandelt wird. Solche Probleme umfassen arithmetische Ausnahmen, wie das Teilen durch Null; Zeigerausnahmen, z. B. der Versuch, über eine Nullreferenz auf ein Objekt zuzugreifen; und Indizieren von Ausnahmen, z. B. der Versuch, über einen zu großen oder zu kleinen Index auf ein Array-Element zuzugreifen.

Es gibt auch eine wichtige Information in der Java-Sprachspezifikation :

Die in der throw-Klausel genannten geprüften Ausnahmeklassen sind Bestandteil des Vertrags zwischen dem Implementierer und dem Benutzer der Methode oder des Konstruktors .

Unterm Strich IMHO ist , dass Sie können jeden fangen RuntimeException, aber Sie sind nicht verpflichtet, und in der Tat ist die Umsetzung nicht die gleichen nicht-geprüfte Ausnahmen geworfen halten erforderlich, da diejenigen , die nicht Bestandteil des Vertrages sind.


Vielen Dank. Noch eine Frage, wenn Sie die sprudeln exception, sollte ich die genaue Ausnahme sprudeln oder sie mit maskieren Exception. Ich schreibe Code über einen alten Code und werde Exceptionüberall in die Luft gesprudelt. Ich frage mich, ob dies das richtige Verhalten ist.
Thang Pham

1
@ Harry Ich werde Leute mit mehr Wissen als ich das beantworten lassen: stackoverflow.com/questions/409563/…
Aleadam

10

1) Nein, eine NumberFormatException ist eine nicht aktivierte Ausnahme. Auch wenn Sie es gefangen haben (das müssen Sie nicht), weil es nicht markiert ist. Dies liegt daran, dass es sich um eine Unterklasse handelt, von IllegalArgumentExceptionder eine Unterklasse von ist RuntimeException.

2) RuntimeExceptionist die Wurzel aller ungeprüften Ausnahmen. Jede Unterklasse von RuntimeExceptionist deaktiviert. Alle anderen Ausnahmen und Throwablewerden mit Ausnahme von Fehlern (die darunter fallen Throwable) überprüft .

3/4) Sie können den Benutzer darauf hinweisen, dass er eine nicht vorhandene Datei ausgewählt und nach einer neuen gefragt hat. Oder beenden Sie einfach die Benachrichtigung des Benutzers, dass er etwas Ungültiges eingegeben hat.

5) Werfen und Fangen 'Exception'ist eine schlechte Praxis. Im Allgemeinen können Sie jedoch andere Ausnahmen auslösen, damit der Anrufer entscheiden kann, wie er damit umgehen soll. Wenn Sie beispielsweise eine Bibliothek zum Lesen einiger Dateieingaben geschrieben haben und Ihrer Methode eine nicht vorhandene Datei übergeben wurde, wissen Sie nicht, wie Sie damit umgehen sollen. Möchte der Anrufer erneut fragen oder beenden? Sie werfen also die Ausnahme in der Kette zurück zum Anrufer.

In vielen Fällen tritt ein unchecked ExceptionFehler auf, weil der Programmierer die Eingaben nicht überprüft hat (im Fall NumberFormatExceptionIhrer ersten Frage). Aus diesem Grund ist es optional, sie abzufangen, da es elegantere Möglichkeiten gibt, diese Ausnahmen nicht zu generieren.


Vielen Dank. Noch eine Frage, wenn Sie die sprudeln exception, sollte ich die genaue Ausnahme sprudeln oder sie mit maskieren Exception. Ich schreibe Code über einen alten Code und werde Exceptionüberall in die Luft gesprudelt. Ich frage mich, ob dies das richtige Verhalten ist.
Thang Pham

Sie können entweder nur Ihre Methode auch eine Ausnahme auslösen lassen (was nicht ideal ist). Oder fangen Sie Exception und werfen Sie eine bessere Exception (wie IOException oder so). Alle Ausnahmen können eine Ausnahme in ihrem Konstruktor als 'Ursache' verwenden, daher sollten Sie diese verwenden.
Dontocsata

8

Aktiviert - Anfällig. Eingecheckt in Kompilierungszeit.

ZB .. FileOperations

Nicht überprüft - Aufgrund fehlerhafter Daten. Zur Laufzeit eingecheckt.

Z.B..

String s = "abc";
Object o = s;
Integer i = (Integer) o;

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at Sample.main(Sample.java:9)

Hier ist eine Ausnahme auf fehlerhafte Daten zurückzuführen, die während der Kompilierungszeit in keiner Weise ermittelt werden können.


6

Überprüfte Ausnahmen werden zur Kompilierungszeit von der JVM und den zugehörigen Ressourcen (Dateien / Datenbank / Stream / Socket usw.) überprüft. Das Motiv der aktivierten Ausnahme ist, dass die Anwendung zur Kompilierungszeit, wenn die Ressourcen nicht verfügbar sind, ein alternatives Verhalten definieren sollte, um dies im catch / finally-Block zu behandeln.

Nicht aktivierte Ausnahmen sind rein programmatische Fehler, falsche Berechnungen, Nulldaten oder sogar Fehler in der Geschäftslogik können zu Laufzeitausnahmen führen. Es ist absolut in Ordnung, ungeprüfte Ausnahmen im Code zu behandeln / abzufangen.

Erklärung von http://coder2design.com/java-interview-questions/


5

Meine absolute Lieblingsbeschreibung des Unterschieds zwischen ungeprüften und geprüften Ausnahmen findet sich im Java Tutorial-Artikel " Ungeprüfte Ausnahmen - die Kontroverse " (es tut mir leid, dass ich in diesem Beitrag alle Grundkenntnisse habe - aber hey, die Grundlagen sind manchmal die besten):

Hier ist die grundlegende Richtlinie: Wenn von einem Client vernünftigerweise erwartet werden kann, dass er sich von einer Ausnahme erholt, machen Sie ihn zu einer aktivierten Ausnahme. Wenn ein Client nichts tun kann, um die Ausnahme wiederherzustellen, machen Sie es zu einer nicht aktivierten Ausnahme

Das Herzstück von "welche Art von Ausnahme zu werfen ist" ist semantisch (bis zu einem gewissen Grad) und das obige Zitat bietet eine ausgezeichnete Richtlinie (daher bin ich immer noch überwältigt von der Vorstellung, dass C # geprüfte Ausnahmen beseitigt hat - insbesondere, wie Liskov argumentiert ihre Nützlichkeit).

Der Rest wird dann logisch: Auf welche Ausnahmen erwartet der Compiler, dass ich explizit antworte? Diejenigen, von denen Sie erwarten, dass sich der Client erholt.


5

Um die letzte Frage zu beantworten (die anderen scheinen oben gründlich beantwortet zu sein): "Soll ich die genaue Ausnahme in die Luft sprudeln lassen oder sie mit Ausnahme maskieren?"

Ich gehe davon aus, dass Sie so etwas meinen:

public void myMethod() throws Exception {
    // ... something that throws FileNotFoundException ...
}

Nein, deklarieren Sie immer die genaueste mögliche Ausnahme oder eine Liste davon. Die Ausnahmen, für die Sie Ihre Methode als auslösungsfähig deklarieren, sind Bestandteil des Vertrags zwischen Ihrer Methode und dem Aufrufer. Werfen "FileNotFoundException"bedeutet, dass der Dateiname möglicherweise nicht gültig ist und die Datei nicht gefunden wird. Der Anrufer muss dies intelligent handhaben. Werfen Exceptionbedeutet "Hey, das passiert nicht. Deal." Welches ist eine sehr arme API.

In den Kommentaren zum ersten Artikel gibt es einige Beispiele, bei denen "throw Exception" eine gültige und vernünftige Deklaration ist, aber das ist bei den meisten " normal" Codes, die Sie jemals schreiben werden , nicht der Fall .


Machen Sie Ihre Check-Exception-Deklaration genau zu einem Teil Ihrer Codedokumentation und helfen Sie der Person, die Ihre Software verwendet.
Salvador Valencia

5

Laufzeitausnahmen : Laufzeitausnahmen werden als nicht aktivierte Ausnahmen bezeichnet. Alle anderen Ausnahmen sind geprüfte Ausnahmen und stammen nicht von java.lang.RuntimeException.

Überprüfte Ausnahmen : Eine geprüfte Ausnahme muss irgendwo im Code abgefangen werden. Wenn Sie eine Methode aufrufen, die eine aktivierte Ausnahme auslöst, die aktivierte Ausnahme jedoch nicht irgendwo abfängt, wird Ihr Code nicht kompiliert. Aus diesem Grund werden sie als geprüfte Ausnahmen bezeichnet: Der Compiler prüft, ob sie behandelt oder deklariert werden.

Einige der Methoden in der Java-API lösen geprüfte Ausnahmen aus, sodass Sie häufig Ausnahmebehandlungsroutinen schreiben, um mit Ausnahmen umzugehen, die von Methoden generiert wurden, die Sie nicht geschrieben haben.


3

Warum lassen sie die Ausnahme aufblasen? Ist es nicht besser, den Fehler früher zu behandeln? Warum sprudeln?

Angenommen, Sie haben eine Client-Server-Anwendung und der Client hat eine Anforderung für eine Ressource gestellt, die nicht herausgefunden werden konnte, oder für einen anderen Fehler, der möglicherweise auf der Serverseite während der Verarbeitung der Benutzeranforderung aufgetreten ist. Dann ist dies die Pflicht des Servers, um dem Client mitzuteilen, warum er das angeforderte Objekt nicht erhalten konnte. Um dies auf der Serverseite zu erreichen, wird Code geschrieben, um die Ausnahme mit dem Schlüsselwort throw auszulösen, anstatt sie zu schlucken oder zu behandeln. Wenn der Server sie behandelt / schluckt In diesem Fall besteht keine Möglichkeit, dem Kunden mitzuteilen, welcher Fehler aufgetreten ist.

Hinweis: Um eine klare Beschreibung des aufgetretenen Fehlertyps zu erhalten, können Sie ein eigenes Ausnahmeobjekt erstellen und an den Client senden.


Guter Punkt. Was es bedeutet, ist es, es auf die oberste verantwortliche Ebene zu bringen, die den Logikfluss steuert und die Geschäftslogik für die Anwendung überwacht. Es wäre beispielsweise unmöglich, dass die Datenbankschicht dem Client mitteilt, dass etwas Kritisches fehlt oder nicht reagiert. Wenn es bis zur obersten Serverebene sprudelt, ist es einfach, die Ansicht des Clients mit einer kritischen Fehlermeldung zu aktualisieren.
Salvador Valencia


3

Ich möchte nur einige Gründe hinzufügen, warum geprüfte Ausnahmen überhaupt nicht verwendet werden. Dies ist keine vollständige Antwort, aber ich denke, sie beantwortet einen Teil Ihrer Frage und ergänzt viele andere Antworten.

Immer wenn geprüfte Ausnahmen betroffen sind, befindet sich throws CheckedExceptionirgendwo in einer Methodensignatur eine ( CheckedExceptionmöglicherweise jede geprüfte Ausnahme). Eine Signatur löst KEINE Ausnahme aus. Das Auslösen von Ausnahmen ist ein Aspekt der Implementierung. Schnittstellen, Methodensignaturen, übergeordnete Klassen, all diese Dinge sollten NICHT von ihren Implementierungen abhängen. Die Verwendung von aktivierten Ausnahmen hier (tatsächlich die Tatsache, dass Sie die throwsin der Methodensignatur deklarieren müssen) bindet Ihre übergeordneten Schnittstellen an Ihre Implementierungen dieser Schnittstellen.

Lassen Sie mich Ihnen ein Beispiel zeigen.

Lassen Sie uns eine schöne und saubere Oberfläche wie diese haben

public interface IFoo {
    public void foo();
}

Jetzt können wir viele Implementierungen von Methoden foo()wie diese schreiben

public class Foo implements IFoo {
    @Override
    public void foo() {
        System.out.println("I don't throw and exception");
    }
}

Class Foo ist vollkommen in Ordnung. Machen wir jetzt einen ersten Versuch in der Klasse Bar

public class Bar implements IFoo {
    @Override
    public void foo() {
        //I'm using InterruptedExcepton because you probably heard about it somewhere. It's a checked exception. Any checked exception will work the same.
        throw new InterruptedException();
    }
}

Diese Klassenleiste wird nicht kompiliert. Da InterruptedException eine aktivierte Ausnahme ist, müssen Sie sie entweder erfassen (mit einem Try-Catch innerhalb der Methode foo ()) oder deklarieren, dass Sie sie auslösen ( throws InterruptedExceptionzur Methodensignatur hinzufügen ). Da ich diese Ausnahme hier nicht erfassen möchte (ich möchte, dass sie sich nach oben ausbreitet, damit ich sie an anderer Stelle richtig verarbeiten kann), ändern wir die Signatur.

public class Bar implements IFoo {
    @Override
    public void foo() throws InterruptedException {
        throw new InterruptedException();
    }
}

Diese Klassenleiste wird auch nicht kompiliert! Die Methode foo () von Bar überschreibt NICHT die Methode foo () von IFoo, da ihre Signaturen unterschiedlich sind. Ich könnte die @ Override-Annotation entfernen, aber ich möchte gegen die Schnittstelle IFoo wie programmieren IFoo foo;und später entscheiden, welche Implementierung ich verwenden möchte, wie foo = new Bar();. Wenn die Methode foo () von Bar die Methode foo von IFoo nicht überschreibt, wenn ich das tuefoo.foo(); wird die Implementierung von foo () von Bar nicht aufgerufen.

Damit Bar public void foo() throws InterruptedExceptionIFoos überschreibt, public void foo()MUSS throws InterruptedExceptionich die Methodensignatur von IFoo ergänzen . Dies führt jedoch zu Problemen mit meiner Foo-Klasse, da sich die Signatur der foo () -Methode von der Signatur der IFoo-Methode unterscheidet. Wenn ich außerdem throws InterruptedExceptionzu Foos Methode foo () hinzufügen würde, würde ich einen weiteren Fehler erhalten, der besagt, dass Foos Methode foo () deklariert, dass sie eine InterruptedException auslöst, aber niemals eine InterruptedException auslöst.

Wie Sie sehen können (wenn ich gute Arbeit geleistet habe, um dieses Zeug zu erklären), zwingt mich die Tatsache, dass ich eine aktivierte Ausnahme wie InterruptedException auslöse, dazu, meine Schnittstelle IFoo an eine ihrer Implementierungen zu binden, was wiederum Chaos bei IFoo verursacht andere Implementierungen!

Dies ist ein wichtiger Grund, warum geprüfte Ausnahmen SCHLECHT sind. In Kappen.

Eine Lösung besteht darin, die aktivierte Ausnahme zu erfassen, sie in eine nicht aktivierte Ausnahme zu verpacken und die nicht aktivierte Ausnahme auszulösen.


2
Ja, es ist schlecht, weil du gesagt hast, du wolltest es nicht fangen. Um jedoch die Unterschrift von IFOO nicht zu beeinträchtigen, müssen Sie dies tun. Ich würde das lieber tun und weitermachen, anstatt alle meine Schnittstellensignaturen neu auszugleichen, um zu vermeiden, dass eine Ausnahme abgefangen wird (nur weil Ausnahmen SCHLECHT sind).
Salvador Valencia

Ja ich stimme zu. Mir war etwas unklar. Ich möchte, dass sich eine Ausnahme verbreitet, damit ich sie woanders behandeln kann. Eine Lösung besteht darin, die InterruptedException abzufangen und eine ungeprüfte Ausnahme auszulösen. dh wir vermeiden geprüfte Ausnahmen und geben ungeprüfte Ausnahmen weiter (auch wenn sie nur als Wrapper sinnvoll sind)
Blueriver

"Dies führt jedoch zu Problemen mit meiner Foo-Klasse, da sich die Signatur der foo () -Methode von der Signatur der IFoo-Methode unterscheidet." Ich habe gerade Ihre Idee getestet, und es ist möglich, sie zu kompilieren, selbst wenn wir throws InterruptedExceptiondie Methodensignatur von IFoo ergänzen , ohne irgendetwas in eine Implementierung zu werfen. Es verursacht also kein wirkliches Problem. Wenn Sie in einer Schnittstelle jeden Methodensignaturwurf ausführen Exception, hat eine Implementierung nur die Wahl, eine Ausnahme auszulösen oder nicht auszulösen (jede Ausnahme, da Exceptionalle Ausnahmen gekapselt sind).
Flyout91

Ich gebe jedoch zu, dass es verwirrend sein kann, denn wenn Sie eine solche Schnittstelle implementieren und auf etwas wie "Nicht implementierte Methoden hinzufügen" klicken, werden sie automatisch mit der throw ExceptionKlausel in ihrer Signatur erstellt, obwohl Ihre Implementierung nichts auslöst oder möglicherweise auslöst eine spezifischere Ausnahme. Aber ich denke immer noch, dass es eine gute Praxis ist, immer eine Ausnahme für die Methode eines Interfaces zu werfen, da der Benutzer wiederum die Wahl hat, etwas zu werfen oder nicht zu werfen.
Flyout91

Dies verfehlt den ganzen Punkt. Der Zweck einer Schnittstelle besteht darin, den Vertrag zu deklarieren, den ein Kunde zur Erfüllung benötigt. Dies kann Fehlerszenarien umfassen, die behandelt werden können. Wenn eine Implementierung auf einen Fehler stößt, sollte sie diesen Fehler dem entsprechenden abstrakten Fehler zuordnen, der von der Clientschnittstelle deklariert wurde.
Erickson

3
  • Java unterscheidet zwei Kategorien von Ausnahmen (aktiviert und deaktiviert).
  • Java erzwingt einen Fang oder eine deklarierte Anforderung für geprüfte Ausnahmen.
  • Der Typ einer Ausnahme bestimmt, ob eine Ausnahme aktiviert oder deaktiviert ist.
  • Alle Ausnahmetypen, die direkt oder indirekt subclasseszur Klasse gehören, RuntimeException sind nicht aktivierte Ausnahmen.
  • Alle Klassen, die von der Klasse erben, Exceptionaber nicht, RuntimeExceptiongelten alschecked exceptions .
  • Klassen, die vom Klassenfehler erben, gelten als deaktiviert.
  • Der Compiler überprüft jeden Methodenaufruf und jede Verzögerung, um festzustellen, ob die Methode ausgelöst wird checked exception.
    • In diesem Fall stellt der Compiler sicher, dass die Ausnahme abgefangen oder in einer throw-Klausel deklariert wird.
  • Um den Deklarationsteil der Catch-or-Declaration-Anforderung zu erfüllen, muss die Methode, die die Ausnahme generiert, eine throwsKlausel bereitstellen , die die checked-exception.
  • Exception Klassen sind so definiert, dass sie überprüft werden, wenn sie als wichtig genug angesehen werden, um sie zu fangen oder zu deklarieren.

2

Hier ist eine einfache Regel, die Ihnen bei der Entscheidung helfen kann. Es hängt damit zusammen, wie Schnittstellen in Java verwendet werden.

Nehmen Sie Ihre Klasse und stellen Sie sich vor, Sie entwerfen eine Schnittstelle dafür, sodass die Schnittstelle die Funktionalität der Klasse beschreibt, jedoch keine der zugrunde liegenden Implementierungen (wie es eine Schnittstelle tun sollte). Stellen Sie sich vor, Sie könnten die Klasse auf andere Weise implementieren.

Schauen Sie sich die Methoden der Schnittstelle an und berücksichtigen Sie die Ausnahmen, die sie möglicherweise auslösen:

Wenn eine Ausnahme unabhängig von der zugrunde liegenden Implementierung von einer Methode ausgelöst werden kann (mit anderen Worten, sie beschreibt nur die Funktionalität), sollte es sich wahrscheinlich um eine aktivierte Ausnahme in der Schnittstelle handeln.

Wenn eine Ausnahme durch die zugrunde liegende Implementierung verursacht wird, sollte sie sich nicht in der Schnittstelle befinden. Daher muss es sich entweder um eine nicht aktivierte Ausnahme in Ihrer Klasse handeln (da nicht aktivierte Ausnahmen nicht in der Schnittstellensignatur enthalten sein müssen), oder Sie müssen sie umbrechen und als überprüfte Ausnahme, die Teil der Schnittstellenmethode ist, erneut auslösen.

Um zu entscheiden, ob Sie einschließen und erneut werfen sollten, sollten Sie erneut überlegen, ob es für einen Benutzer der Benutzeroberfläche sinnvoll ist, die Ausnahmebedingung sofort zu behandeln, oder ob die Ausnahme so allgemein ist, dass Sie nichts dagegen tun können und dies sollte den Stapel verbreiten. Ist die umschlossene Ausnahme sinnvoll, wenn sie als Funktionalität der neuen Schnittstelle ausgedrückt wird, die Sie definieren, oder ist sie nur ein Träger für eine Reihe möglicher Fehlerzustände, die auch bei anderen Methoden auftreten können? In diesem Fall handelt es sich möglicherweise immer noch um eine aktivierte Ausnahme, andernfalls sollte sie deaktiviert sein.

Normalerweise sollten Sie keine "Bubble-up" -Ausnahmen (Fangen und erneutes Werfen) planen. Entweder sollte eine Ausnahme vom Anrufer behandelt werden (in diesem Fall ist sie aktiviert), oder sie sollte bis zu einem High-Level-Handler reichen (in diesem Fall ist es am einfachsten, wenn sie deaktiviert ist).


2

Nur um darauf hinzuweisen, dass Sie die Ausnahme in der Signatur jeder Methode zwischen Ihnen und dem Fang deklarieren müssen, wenn Sie eine aktivierte Ausnahme in einen Code auslösen und der Fang nur wenige Ebenen darüber liegt. Die Kapselung ist also fehlerhaft, da alle Funktionen im Wurfpfad die Details dieser Ausnahme kennen müssen.


2

Kurz gesagt, Ausnahmen, die Ihr Modul oder die oben genannten Module zur Laufzeit behandeln sollen, werden als geprüfte Ausnahmen bezeichnet. andere sind ungeprüfte Ausnahmen, die entweder RuntimeExceptionoder sindError .

In diesem Video werden aktivierte und deaktivierte Ausnahmen in Java erläutert:
https://www.youtube.com/watch?v=ue2pOqLaArw


1

All dies sind geprüfte Ausnahmen. Nicht aktivierte Ausnahmen sind Unterklassen von RuntimeException. Die Entscheidung ist nicht, wie man mit ihnen umgeht, sondern ob Ihr Code sie wirft. Wenn Sie nicht möchten, dass der Compiler Ihnen mitteilt, dass Sie keine Ausnahme behandelt haben, verwenden Sie eine nicht aktivierte Ausnahme (Unterklasse von RuntimeException). Diese sollten für Situationen gespeichert werden, die Sie nicht wiederherstellen können, z. B. Speicherfehler und dergleichen.


Äh. Wenn NumberFormatException eine aktivierte Ausnahme ist, wie Sie sagen, widerspricht sie nicht der Tatsache, dass sie von RuntimeException geerbt wurde ?
Eis

Entschuldigung, ich war nicht sehr klar. Ich bezog mich auf die FileNotFoundException, nicht auf die NumberFormatException. Basierend auf seinen # 2 & # 4 schien es, als ob er dachte, dass Checked vs. Unchecked darauf basiert, wie Sie die Ausnahme behandelt haben, nachdem Sie sie abgefangen haben. Nicht wie es definiert wurde.
Mamboking

-1

Wenn sich jemand für einen weiteren Beweis interessiert, der geprüfte Ausnahmen nicht mag, lesen Sie die ersten Absätze der beliebten JSON-Bibliothek:

"Obwohl dies eine aktivierte Ausnahme ist, kann sie nur selten wiederhergestellt werden. Die meisten Anrufer sollten diese Ausnahme einfach in eine nicht aktivierte Ausnahme einschließen und erneut auslösen:"

Warum in aller Welt sollte irgendjemand Entwickler dazu bringen, die Ausnahme weiter zu überprüfen, wenn wir sie stattdessen "einfach einpacken" sollten? lol

http://developer.android.com/reference/org/json/JSONException.html


4
Weil nur die meisten Anrufer, nicht alle Anrufer, einpacken und neu werfen sollten. Die Tatsache, dass die Ausnahme aktiviert ist, bedeutet, dass der Anrufer darüber nachdenken muss, ob er einer der "meisten" Anrufer oder eine der Minderheiten ist, die die Ausnahme behandeln können und sollten.
Warren Dew

1
Wenn Sie Fehler bei jedem Aufruf überprüfen möchten, gehen Sie zurück zu C. Ausnahmen sind eine Möglichkeit, die normale Programmausführung von abnormalen zu trennen, ohne Ihren Code zu verschmutzen. Ausnahmen stellen sicher, dass Sie einen Fehler auf einer bestimmten Ebene nicht stillschweigend ignorieren können .
Slawomir

-1

Überprüfte Ausnahmen :

  • Die Ausnahmen, die vom Compiler zur reibungslosen Ausführung des Programms zur Laufzeit geprüft werden, werden als geprüfte Ausnahme bezeichnet.

  • Diese treten zur Kompilierungszeit auf.

  • Wenn diese nicht ordnungsgemäß behandelt werden, wird ein Fehler bei der Kompilierung angezeigt (keine Ausnahme).
  • Alle Unterklassen der Exception-Klasse mit Ausnahme von RuntimeException sind Checked Exception.

    Hypothetisches Beispiel - Angenommen, Sie verlassen Ihr Haus für die Prüfung. Wenn Sie jedoch prüfen, ob Sie Ihr Hallenticket zu Hause mitgenommen haben (Kompilierungszeit), tritt in der Prüfungshalle (Laufzeit) kein Problem auf.

Deaktivierte Ausnahme :

  • Die Ausnahmen, die vom Compiler nicht geprüft werden, werden als ungeprüfte Ausnahmen bezeichnet.

  • Diese treten zur Laufzeit auf.

  • Wenn diese Ausnahmen nicht ordnungsgemäß behandelt werden, wird kein Fehler bei der Kompilierung angezeigt. Das Programm wird jedoch zur Laufzeit vorzeitig beendet.

  • Alle Unterklassen von RunTimeException und Error sind nicht aktivierte Ausnahmen.

    Hypothetisches Beispiel - Angenommen, Sie befinden sich in Ihrer Prüfungshalle, aber Ihre Schule hatte irgendwie einen Brandunfall (dh zur Laufzeit), bei dem Sie zu diesem Zeitpunkt nichts tun können, aber vorher Vorsichtsmaßnahmen getroffen werden können (Kompilierungszeit).


-2

Alle Ausnahmen müssen überprüft werden.

  1. Ungeprüfte Ausnahmen sind uneingeschränkte Gotos. Und uneingeschränkte Gotos gelten als eine schlechte Sache.

  2. Nicht aktivierte Ausnahmen unterbrechen die Kapselung. Um sie korrekt zu verarbeiten, müssen alle Funktionen im Aufrufbaum zwischen dem Werfer und dem Catcher bekannt sein, um Fehler zu vermeiden.

  3. Ausnahmen sind Fehler in der Funktion, die sie auslöst, aber keine Fehler in der Funktion, die sie verarbeitet. Der Zweck von Ausnahmen besteht darin, dem Programm eine zweite Chance zu geben, indem die Entscheidung, ob es sich um einen Fehler handelt oder nicht, auf einen anderen Kontext verschoben wird. Nur im anderen Kontext kann die richtige Entscheidung getroffen werden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.