756 Stimmen

Überprüfte und ungeprüfte Ausnahmen in Java verstehen

Joshua Bloch in " Leistungsfähiges Java " sagte, dass

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

Mal sehen, ob ich das richtig verstehe.

Hier ist mein Verständnis einer geprü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. Handelt es sich um eine kontrollierte Ausnahme?

2. Ist RuntimeException eine ungeprüfte 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 auf diese Weise wiederherzustellen? Kann ich das? (Anmerkung: meine 3. Frage befindet sich innerhalb der catch oben)

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 tun die Menschen das?

public void someMethod throws Exception{

}

Warum lassen sie die Ausnahme aufsprudeln? Ist es nicht besser, den Fehler früher zu behandeln? Warum aufblähen?

6. Soll ich die genaue Ausnahme aufblasen oder sie mit Exception maskieren?

Im Folgenden finden Sie meine Lektüre

Wann sollte ich in Java eine geprüfte Ausnahme erstellen, und wann eine Laufzeitausnahme?

Wann sind kontrollierte und nicht kontrollierte Ausnahmen zu wählen?

8 Stimmen

Ich habe ein gutes Beispiel für eine ungeprüfte Ausnahme. Ich habe eine DataSeries Klasse, die Daten enthält, die immer in zeitlicher Reihenfolge bleiben müssen. Es gibt eine Methode zum Hinzufügen einer neuen DataPoint an das Ende einer DataSeries . Wenn mein gesamter Code im gesamten Projekt korrekt funktioniert, ist eine DataPoint sollte niemals an das Ende angefügt werden, das ein älteres Datum als das bereits vorhandene hat. Jedes Modul im gesamten Projekt ist nach dieser Binsenweisheit aufgebaut. Ich überprüfe jedoch diese Bedingung und werfe eine ungeprüfte Ausnahme, wenn sie eintritt. Und warum? Wenn es passiert, möchte ich wissen, wer das macht, und es beheben.

3 Stimmen

Um noch mehr Verwirrung zu stiften. Viele Leute haben vor ~10 Jahren geprüfte Ausnahmen befürwortet, aber die Ansicht geht heute mehr und mehr in Richtung "geprüfte Ausnahmen sind schlecht". (Ich stimme dem allerdings nicht zu)

0 Stimmen

516voto

Bozho Punkte 570413

Viele Leute sagen, dass geprüfte Ausnahmen (d. h. solche, die man explizit abfangen oder erneut auslösen sollte) überhaupt nicht verwendet werden sollten. Sie wurden zum Beispiel in C# abgeschafft, und die meisten Sprachen haben sie nicht. Sie können also immer eine Unterklasse von RuntimeException (ungeprüfte Ausnahme)

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

Hier meine ausführliche Stellungnahme zu diesem Thema .

Was die einzelnen Fragen betrifft:

  1. Ist die NumberFormatException eine kontrollierte Ausnahme in Betracht ziehen?
    Nein. NumberFormatException nicht angekreuzt ist (= ist Unterklasse von RuntimeException ). Und warum? Ich weiß es nicht. (aber es hätte eine Methode geben müssen isValidInteger(..) )

  2. Ist RuntimeException eine ungeprüfte Ausnahme?
    Ja, genau.

  3. Was soll ich hier tun?
    Es kommt darauf an, wo sich dieser Code befindet und was Sie damit erreichen wollen. Befindet er sich in der UI-Schicht - fangen Sie ihn ab und zeigen Sie eine Warnung an; befindet er sich in der Diensteschicht - fangen Sie ihn überhaupt nicht ab - lassen Sie ihn sprudeln. Verschlucken Sie die Ausnahme einfach nicht. Wenn in den meisten Fällen eine Ausnahme auftritt, sollten Sie sich für eine der beiden Möglichkeiten entscheiden:

    • protokollieren und zurückgeben
    • rethrow it (deklarieren, dass es von der Methode ausgelöst wird)
    • eine neue Ausnahme konstruieren, indem die aktuelle im Konstruktor übergeben wird
  4. Könnte der obige Code nicht auch eine geprüfte Ausnahme sein? Kann ich versuchen, die Situation auf diese Weise wiederherzustellen? Kann ich das?
    Das könnte es gewesen sein. Aber nichts hindert Sie daran, auch die ungeprüfte Ausnahme abzufangen

  5. Warum fügen Menschen Klasse hinzu? Exception in der Wurfklausel?
    Meistens, weil die Leute zu faul sind, um zu überlegen, was sie fangen und was sie wieder wegwerfen sollen. Werfen Exception ist eine schlechte Praxis und sollte vermieden werden.

Leider gibt es keine einheitliche Regel, mit der Sie bestimmen können, wann Sie Ausnahmen abfangen, wann Sie sie erneut auslösen, wann Sie geprüfte und wann Sie ungeprüfte Ausnahmen verwenden sollten. Ich stimme zu, dass dies viel Verwirrung und eine Menge schlechten Code verursacht. Das allgemeine Prinzip wird von Bloch dargelegt (Sie haben einen Teil davon zitiert). Und das allgemeine Prinzip ist, eine Ausnahme auf die Ebene zurückzuwerfen, auf der man sie behandeln kann.

257voto

Michael Borgwardt Punkte 334642

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 der Ausnahmeklassen. Alles, was eine Unterklasse von Exception außer para RuntimeException und seine Unterklassen ist eine geprüfte Ausnahme.

Der Java-Compiler zwingt Sie, geprüfte Ausnahmen entweder abzufangen oder in der Methodensignatur zu deklarieren. Damit sollte die Programmsicherheit verbessert werden, aber die Mehrheitsmeinung scheint zu sein, dass dies die damit verbundenen Designprobleme nicht wert ist.

Warum lassen sie die Ausnahme aufsteigen? Ist die Fehlerbehandlung nicht je früher, desto besser? Warum aufblähen?

Denn das ist die ganze Punkt von 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 in Methoden auf niedriger Ebene zu behandeln, wo sie ursprünglich auftreten.

78voto

d-live Punkte 7802
  1. Handelt es sich dabei um eine kontrollierte Ausnahme? Nein Die Tatsache, dass Sie eine Ausnahme behandeln, macht sie nicht zu einer Checked Exception wenn es sich um eine RuntimeException .

  2. Ist RuntimeException eine unchecked exception ? Ja

Checked Exceptions sind subclasses de java.lang.Exception Unchecked Exceptions sind subclasses de java.lang.RuntimeException

Aufrufe, die geprüfte Ausnahmen auslösen, müssen in einen try{}-Block eingeschlossen werden oder auf einer höheren Ebene im Aufrufer der Methode behandelt werden. In diesem Fall muss die aktuelle Methode erklären, dass sie diese Ausnahmen auslöst, damit die Aufrufer geeignete Vorkehrungen zur Behandlung der Ausnahme treffen können.

Ich hoffe, das hilft.

F: Soll ich die exakte Ausnahme aufblasen oder sie mit Exception maskieren?

A: Ja, das ist eine sehr gute Frage und eine wichtige Designüberlegung. Die Klasse Exception ist eine sehr allgemeine Ausnahmeklasse und kann verwendet werden, um interne Ausnahmen auf niedriger Ebene zu verpacken. Es ist besser, eine benutzerdefinierte Ausnahme zu erstellen und darin zu verpacken. Aber, und das ist ein wichtiger Punkt, man darf niemals die zugrundeliegende Ursache verdecken. Zum Beispiel, Don't ever Folgendes tun -

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

Tun Sie stattdessen Folgendes:

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

Das Aufspüren der ursprünglichen Ursache vergräbt die eigentliche Ursache, die nicht wiederhergestellt werden kann, und ist ein Alptraum für die Support-Teams, die nur Zugang zu Anwendungsprotokollen und Fehlermeldungen haben. Letzteres ist zwar besser, wird aber von vielen Leuten nicht genutzt, weil die Entwickler es einfach versäumen, die zugrunde liegende Meldung an den Aufrufer weiterzugeben. Merken Sie sich das also gut: Always pass on the actual exception zurück, unabhängig davon, ob sie in eine anwendungsspezifische Ausnahme eingeschlossen sind oder nicht.

Zum Try-Catching RuntimeExceptions

RuntimeException s sollten in der Regel nicht mit try-catched werden. Sie signalisieren im Allgemeinen einen Programmierfehler und sollten in Ruhe gelassen werden. Stattdessen sollte der Programmierer die Fehlerbedingung prüfen, bevor er einen Code aufruft, der zu einem Fehler führen könnte. 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 Null-Prüfung durchgeführt werden müssen wie -

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

Es gibt jedoch Fälle, in denen eine solche Fehlerprüfung teuer ist, wie z. B. bei der Formatierung von Zahlen, wie hier -

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 sie im Wesentlichen bedeutet, dass der gesamte Code für die Umwandlung von Zeichenketten in Ganzzahlen in der parseInt()-Methode dupliziert werden muss - und fehleranfällig ist, wenn sie von einem Entwickler implementiert wird. Daher ist es besser, einfach auf try-catch zu verzichten.

Also NullPointerException y NumberFormatException sind beide RuntimeExceptions und fängt eine NullPointerException sollte durch eine anmutige Null-Prüfung ersetzt werden, während ich empfehle, eine NumberFormatException ausdrücklich, um die Einführung von fehleranfälligem Code zu vermeiden.

10voto

dontocsata Punkte 2981

1) Nein, eine NumberFormatException ist eine ungeprüfte Exception. Auch wenn Sie sie abgefangen haben (was Sie nicht tun müssen), weil sie ungeprüft ist. Der Grund dafür ist, dass es sich um eine Unterklasse von IllegalArgumentException die eine Unterklasse von RuntimeException .

2) RuntimeException ist die Wurzel aller ungeprüften Ausnahmen. Jede Unterklasse von RuntimeException ist nicht angekreuzt. Alle anderen Ausnahmen und Throwable werden geprüft, außer bei Fehlern (diese fallen unter Throwable ).

3/4) Sie könnten den Benutzer darauf hinweisen, dass er eine nicht vorhandene Datei ausgewählt hat, und ihn um eine neue Datei bitten. Oder einfach aufhören, den Benutzer zu informieren, dass er etwas Ungültiges eingegeben hat.

5) Werfen und Fangen 'Exception' ist schlechte Praxis. Generell können Sie aber auch andere Ausnahmen auslösen, damit der Aufrufer entscheiden kann, wie er damit umgehen will. Wenn Sie z. B. eine Bibliothek geschrieben haben, die das Lesen einer Datei verarbeiten soll, und Ihrer Methode eine nicht existierende Datei übergeben wird, wissen Sie nicht, wie Sie damit umgehen sollen. Soll der Aufrufer noch einmal nachfragen oder aufgeben? Also werfen Sie die Exception die Kette hinauf zurück zum Aufrufer.

In vielen Fällen wird ein unchecked Exception auftritt, weil der Programmierer die Eingaben nicht überprüft hat (im Fall von NumberFormatException in Ihrer ersten Frage). Deshalb ist es optional, sie abzufangen, denn es gibt elegantere Möglichkeiten, die Erzeugung dieser Ausnahmen zu vermeiden.

9voto

bharanitharan Punkte 2389

Abgehakt - Kann vorkommen. Überprüft in der Kompilierzeit.

Beispiel. FileOperations

Nicht angekreuzt - Aufgrund von schlechten Daten. Geprüft während der Laufzeit.

Beispiel.

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 die Ausnahme auf fehlerhafte Daten zurückzuführen und kann in keiner Weise während der Kompilierungszeit bestimmt werden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X