zeilenumbruch - Java: überprüft gegen ungeprüfte Ausnahmeerklärung




jlabel set text (14)

Ich habe mehrere Beiträge zu StackOverFlow über checked vs unchecked Ausnahmen gelesen. Ich bin ehrlich gesagt immer noch nicht ganz sicher, wie man sie richtig benutzt.

Joshua Bloch in " Effektivem Java " sagte das

Verwenden Sie geprüfte Ausnahmen für wiederherstellbare Bedingungen und Laufzeitausnahmen für Programmierfehler (Punkt 58 in 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. Ist das Obige eine geprüfte Ausnahme?

2. Ist RuntimeException eine ungeprüfte Ausnahme?

Hier ist mein Verständnis einer unkontrollierten 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? Ich kann versuchen, die Situation so wiederherzustellen? Kann ich? (Anmerkung: meine 3. Frage ist oben im catch )

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 Leute das?

public void someMethod throws Exception{

}

Warum lassen sie die Ausnahme platzen? Behandeln Sie den Fehler nicht früher besser? Warum sprudeln?

EDIT: Sollte ich die genaue Ausnahme aufblasen oder sie mit Ausnahme maskieren?

Unten sind meine Lesungen

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

Wann wählen Sie die aktivierten und deaktivierten Ausnahmen aus


  1. Ist das Obige eine geprüfte Ausnahme? Nein Die Tatsache, dass Sie eine Ausnahme behandeln, macht sie nicht zu einer aktivierten Ausnahme, wenn es sich um eine RuntimeException handelt.

  2. Ist RuntimeException eine ungeprüfte Ausnahme? Ja

Geprüfte Ausnahmen sind Unterklassen von java.lang.Exception Unchecked Exceptions sind Unterklassen von java.lang.RuntimeException

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

Hoffe das hilft.

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

A: Ja, das ist eine sehr gute Frage und wichtige Designüberlegung. Die Klasse Exception ist eine sehr allgemeine Exception-Klasse und kann zum Umbrechen interner Low-Level-Exceptions verwendet werden. Sie würden besser eine benutzerdefinierte Ausnahme erstellen und darin umbrechen. Aber, und ein großer - nie in der zugrunde liegenden ursprünglichen Ursache verschleiern. Zum Beispiel, tun Sie Dont ever Folge -

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

Stattdessen folgendes tun:

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

Das Weglassen der ursprünglichen Ursache vergräbt die eigentliche Ursache, die über die Wiederherstellung hinausgeht, ist ein Albtraum für Produktions-Supportteams, bei denen ihnen nur Zugriff auf Anwendungsprotokolle und Fehlermeldungen gewährt wird. Obwohl letzteres ein besseres Design ist, verwenden viele Leute es nicht oft, weil Entwickler die zugrundeliegende Nachricht nicht an den Anrufer weitergeben. Machen Sie also eine feste Anmerkung: Always pass on the actual exception zurück, unabhängig davon, ob sie in eine anwendungsspezifische Ausnahme eingeschlossen ist oder nicht.

Auf Versuch-fangende RuntimeExceptions

RuntimeExceptions sollten als allgemeine Regel nicht versucht werden. Sie signalisieren im Allgemeinen einen Programmierfehler und sollten in Ruhe gelassen werden. Stattdessen sollte der Programmierer die Fehlerbedingung prüfen, bevor er Code aufruft, der zu einer RuntimeException führen könnte. Für Beispiel:

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

Dies ist eine schlechte Programmierpraxis. Stattdessen sollte ein Null-Check wie gemacht worden sein -

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 ist die Fehlerprüfung vor dem Aufruf den Aufwand nicht wert, weil es im Wesentlichen bedeutet, den gesamten String-zu-Integer-Konvertierungscode innerhalb der Methode parseInt () zu duplizieren - und ist fehleranfällig, wenn es von einem Entwickler implementiert wird. Es ist also besser, den Versuch zu vereiteln.

Daher sind sowohl NullPointerException als auch NumberFormatException RuntimeExceptions. Wenn eine NullPointerException abgefangen wird, sollte sie durch einen graden Null-Check ersetzt werden, während ich empfehle, NumberFormatException explizit abzufangen, um die mögliche Einführung von fehleranfälligem Code zu vermeiden.


Überprüft - Prone zu passieren. Check-in Kompilierzeit.

ZB .. FileOperations

Unüberprüft - Aufgrund fehlerhafter Daten. Eingecheckte Laufzeit.

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 liegt die Ausnahme an schlechten Daten und kann in keiner Weise während der Kompilierzeit bestimmt werden.


1. Wenn Sie sich über eine 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 ausdehnt.

3 . Es gibt keine Notwendigkeit, die gleiche Ausnahme zu fangen und zu werfen. Sie können in diesem Fall einen neuen Dateidialog anzeigen.

4. FileNotFoundException ist bereits eine geprüfte Ausnahme.

5. Wenn erwartet wird, dass die Methode, die someMethod , die Ausnahme someMethod , kann letztere ausgelöst werden. Es "nur den Ball passiert". Ein Beispiel dafür 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 entschieden, eine Methode zu erzwingen, um alle nicht abgefangenen geprüften Ausnahmen anzugeben, die in ihrem Gültigkeitsbereich enthalten sein 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 über die Ausnahmen Bescheid wissen, die eine Methode auslösen kann, damit sie entscheiden können, was mit ihnen geschehen soll. Diese Ausnahmen sind ebenso ein Teil der Programmierschnittstelle dieser Methode wie ihre Parameter und der 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 sollten Sie nicht auch Laufzeitausnahmen angeben?" Laufzeitausnahmen stellen Probleme dar, die das Ergebnis eines Programmierproblems sind, und daher kann von dem API-Clientcode vernünftigerweise nicht erwartet werden, dass er von ihnen wiederhergestellt oder in irgendeiner Weise behandelt wird. Zu solchen Problemen gehören arithmetische Ausnahmen, z. B. durch Division durch Null; Zeigerausnahmen, z. B. der Versuch, über eine Nullreferenz auf ein Objekt zuzugreifen; und Indizieren von Ausnahmen, wie beispielsweise der Versuch, auf ein Array-Element über einen Index zuzugreifen, der zu groß oder zu klein ist.

Es gibt auch eine wichtige Information in der Java Language Specification :

Die überprüften Ausnahmeklassen, die in der throws-Klausel genannt werden, sind Teil des Vertrags zwischen dem Implementierer und dem Benutzer der Methode oder des Konstruktors .

Die unterste Zeile IMHO ist, dass Sie eine beliebige RuntimeException abfangen können, aber Sie sind nicht dazu verpflichtet, und tatsächlich ist es nicht erforderlich, dass die Implementierung dieselben nicht geprüften Ausnahmen enthält, da diese nicht Teil des Vertrags sind.


Geprüfte Ausnahmen werden zum Zeitpunkt der Kompilierung von der JVM und ihren Resourcen (files / db / stream / socket usw.) geprüft. Das Motiv der geprüften Ausnahme ist, dass zur Kompilierungszeit, wenn die Ressourcen nicht verfügbar sind, die Anwendung ein alternatives Verhalten definieren sollte, um dies im Block catch / finally zu behandeln.

Ungeprüfte 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, unkontrollierte Ausnahmen im Code zu behandeln.

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


Ich möchte nur ein paar Gründe hinzufügen, um keine geprüften Ausnahmen zu verwenden. Dies ist keine vollständige Antwort, aber ich denke, dass es einen Teil Ihrer Frage beantwortet und viele andere Antworten ergänzt.

Wenn checked exceptions betroffen sind, gibt es ein throws CheckedException irgendwo in einer Methodensignatur ( CheckedException kann jede geprüfte Ausnahme sein). Eine Signatur wirft KEINE Exception, Exceptions zu werfen ist ein Aspekt der Implementierung. Schnittstellen, Methodensignaturen, Elternklassen, all diese Dinge sollten NICHT von ihren Implementierungen abhängen. Die Verwendung überprüfter Exceptions hier (eigentlich die Tatsache, dass Sie die throws in der Methodensignatur deklarieren müssen) bindet Ihre überlagerten Interfaces an Ihre Implementierungen dieser Interfaces.

Lass mich dir ein Beispiel zeigen.

Lass uns eine schöne und saubere Oberfläche haben

public interface IFoo {
    public void foo();
}

Jetzt können wir viele Implementierungen der Methode foo() schreiben, wie diese

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

Klasse Foo ist völlig in Ordnung. Jetzt machen wir 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 geprüfte Ausnahme ist, müssen Sie sie entweder erfassen (mit einer try-catch-Methode foo ()) oder deklarieren, dass Sie sie werfen (das Hinzufügen von throws InterruptedException zur Methodensignatur). Da ich diese Ausnahme hier nicht erfassen möchte (ich möchte, dass sie sich nach oben ausbreitet, damit ich sie anderswo richtig behandeln 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! Bars Methode foo () überschreibt NICHT die IFoo-Methode foo (), da ihre Signaturen unterschiedlich sind. Ich könnte die @Override Annotation entfernen, aber ich möchte gegen die Schnittstelle IFoo wie IFoo foo; und später entscheiden, welche Implementierung ich verwenden möchte, wie foo = new Bar(); . Wenn Bars Methode foo () IFoo's Methode foo nicht überschreibt, wenn ich foo.foo(); Es wird Bars Implementierung von foo () nicht aufrufen.

Um public void foo() throws InterruptedException löst public void foo() throws InterruptedException IFoo's public void foo() überschreiben, MUSS ich die throws InterruptedException zu IFoo's Methodensignatur hinzufügen. Dies wird jedoch Probleme mit meiner Foo-Klasse verursachen, da sich die Signatur der foo () -Methode von der Methodensignatur von IFoo unterscheidet. Außerdem, wenn ich die throws InterruptedException zu Foos Methode foo () hinzufügen würde, würde ich einen weiteren Fehler bekommen, der besagt, dass Foo's Methode foo () deklariert, dass sie eine InterruptedException auslöst, aber niemals eine InterruptedException auslöst.

Wie Sie sehen können (wenn ich einen anständigen Job gemacht habe, diese Dinge zu erklären), zwingt mich die Tatsache, dass ich eine geprüfte Ausnahme wie InterruptedException werfe, mein Interface IFoo an eine seiner Implementierungen zu binden, was wiederum auf IFoo's Chaos verursacht andere Implementierungen!

Dies ist ein wichtiger Grund, warum checked Ausnahmen BAD sind. In Großbuchstaben.

Eine Lösung besteht darin, die geprüfte Ausnahme zu erfassen, sie in eine ungeprüfte Ausnahme umzubrechen und die ungeprüfte Ausnahme auszugeben.


Ob etwas eine "geprüfte Ausnahme" ist, hat nichts damit zu tun, ob Sie es fangen oder was Sie im Catch-Block machen. Es ist eine Eigenschaft von Ausnahmeklassen. Alles, was eine Unterklasse von Exception außer RuntimeException und seinen Unterklassen ist, ist eine geprüfte Ausnahme.

Der Java-Compiler zwingt Sie, entweder überprüfte Ausnahmen abzufangen oder sie in der Methodensignatur zu deklarieren. Es sollte die Programmsicherheit verbessern, aber die Mehrheitsmeinung scheint zu sein, dass es die Designprobleme, die es schafft, nicht wert ist.

Warum lassen sie die Ausnahme platzen? Ist kein Handle-Fehler, 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 dazu zu zwingen, sie in Low-Level-Methoden zu behandeln, in denen sie ursprünglich auftreten.


Viele Leute sagen, dass überprüfte Ausnahmen (dh diese, die Sie explizit abfangen oder erneut aufziehen sollten) überhaupt nicht verwendet werden sollten. Sie wurden zum Beispiel in C # eliminiert, und die meisten Sprachen haben sie nicht. Sie können also immer eine Unterklasse von RuntimeException ( RuntimeException exception)

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

Hier ist meine erweiterte Sicht auf das Thema .

Wie für die besonderen Fragen:

  1. Berücksichtigt die NumberFormatException eine geprüfte Ausnahme?
    Nein. NumberFormatException ist NumberFormatException (= ist eine Unterklasse von RuntimeException ). Warum? Ich weiß es nicht. (aber es hätte eine Methode geben sollen isValidInteger(..) )

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

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

    • log es und zurück
    • wiederholen Sie es (erklären Sie es durch die Methode geworfen zu werden)
    • Konstruieren Sie eine neue Ausnahme, indem Sie die aktuelle Ausnahme im Konstruktor übergeben
  4. Kann der obige Code nicht auch eine geprüfte Ausnahme sein? Ich kann versuchen, die Situation so wiederherzustellen? Kann ich?
    Es hätte sein können. Aber nichts hindert Sie daran, auch die ungeprüfte Ausnahme zu erfassen

  5. Warum fügen Menschen in der throws-Klausel die Klasse Exception ?
    Meistens weil die Leute faul sind, darüber nachzudenken, was sie fangen und was sie erneut versuchen sollen. Eine Exception werfen ist eine schlechte Übung und sollte vermieden werden.

Leider gibt es keine einzige Regel, mit der Sie bestimmen können, wann Sie abfangen, wann Sie sie erneut ausführen, wann Sie checked und wann unchecked Ausnahmen verwenden sollen. Ich stimme zu, 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 für die Ebene erneut auszulösen, in der Sie damit umgehen können.


Checked Exceptions :

  • The exceptions which are checked by the compiler for smooth execution of the program at runtime are called Checked Exception.

  • These occur at compile time.

  • If these are not handled properly, they will give compile time error (Not Exception).
  • All subclasses of Exception class except RuntimeException are Checked Exception.

    Hypothetical Example - Suppose you are leaving your house for the exam, but if you check whether you took your Hall Ticket at home(compile time) then there won't be any problem at Exam Hall(runtime).

Unchecked Exception :

  • The exceptions which are not checked by the compiler are called Unchecked Exceptions.

  • These occur at runtime.

  • If these exceptions are not handled properly, they don't give compile time error. But the program will be terminated prematurely at runtime.

  • All subclasses of RunTimeException and Error are unchecked exceptions.

    Hypothetical Example - Suppose you are in your exam hall but somehow your school had a fire accident (means at runtime) where you can't do anything at that time but precautions can be made before (compile time).


Warum lassen sie die Ausnahme platzen? Behandeln Sie den Fehler nicht früher besser? Warum sprudeln?

Nehmen wir zum Beispiel an, Sie hätten eine Client-Server-Anwendung und der Client hätte eine Anfrage für eine Ressource gestellt, die nicht gefunden werden konnte oder für einen anderen Fehler. Einige sind auf der Serverseite aufgetreten, während die Benutzeranforderung verarbeitet wurde des Servers, um dem Client zu sagen, warum er das Ding, das er angefordert hat, nicht bekommen konnte, um das auf Server-Seite zu erreichen, wird Code geschrieben, um die Ausnahme mit throw keyword zu werfen , anstatt es zu schlucken oder zu handhaben Dann wird es keine Chance geben, dem Kunden mitzuteilen, welcher Fehler aufgetreten ist.

Hinweis: Um eine klare Beschreibung des Fehlertyps zu geben, können wir ein eigenes Exception-Objekt erstellen und es an den Client übergeben.


All exceptions must be checked exceptions.

  1. Unchecked exceptions are unrestricted gotos. And unrestricted gotos are considered a bad thing.

  2. Unchecked exceptions break encapsulation. To process them correctly, all the functions in the call tree between the thrower and the catcher must be known to avoid bugs.

  3. Exceptions are errors in the function that throws them but not errors in the function that processes them. The purpose of exceptions is to give the program a second chance by deferring the decision of whether it's an error or not to another context. It's only in the other context can the correct decision be made.



If anybody cares for yet another proof to dislike checked exceptions, see the first few paragraphs of the popular JSON library:

"Although this is a checked exception, it is rarely recoverable. Most callers should simply wrap this exception in an unchecked exception and rethrow: "

So why in the world would anyone make developers keep checking the exception, if we should "simply wrap it" instead? lol

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


Just to point out that if you throw a checked exception in a code and the catch is few levels above, you need to declare the exception in the signature of each method between you and the catch. So, encapsulation is broken because all functions in the path of throw must know about details of that exception.


My absolute favorite description of the difference between unchecked and checked exceptions is provided by the Java Tutorial trail article, " Unchecked Exceptions - the Controversy " (sorry to get all elementary on this post - but, hey, the basics are sometimes the best):

Here's the bottom line guideline: If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception

The heart of "what type of exception to throw" is semantic (to some degree) and the above quote provides and excellent guideline (hence, I am still blown away by the notion that C# got rid of checked exceptions - particularly as Liskov argues for their usefulness).

The rest then becomes logical: to which exceptions does the compiler expect me to respond, explicitly? The ones from which you expect client to recover.





unchecked-exception