Würfe oder versuchen zu fangen

77

Was ist die allgemeine Faustregel bei der Entscheidung, ob throwseiner Methode eine Klausel hinzugefügt oder eine verwendet werden soll try-catch?

Nach dem, was ich selbst gelesen habe, throwssollte das verwendet werden, wenn der Anrufer sein Vertragsende gebrochen hat (übergebenes Objekt), und das try-catchsollte verwendet werden, wenn während einer Operation, die innerhalb der Methode ausgeführt wird, eine Ausnahme auftritt. Ist das richtig? Wenn ja, was ist auf der Anruferseite zu tun?

PS: Durch Google und SO gesucht, möchte aber eine klare Antwort auf diese Frage.

James P.
quelle
4
Ich war schon immer ein Fan des Ansatzes "Wenn es Sinn macht, hier damit umzugehen ... dann mach es".
CheesePls
Ich möchte, dass alle meine Ausnahmen dort behandelt werden, wo sie auftreten, damit ich mich nicht um die Zukunft kümmern muss.
Doug Hauf

Antworten:

58
  • Eine Ausnahme nur abfangen, wenn Sie damit sinnvoll umgehen können
  • Deklarieren Sie, die Ausnahme nach oben zu werfen, wenn sie vom Verbraucher der aktuellen Methode behandelt werden soll
  • Ausnahmen auslösen, wenn sie durch die Eingabeparameter verursacht werden (diese werden jedoch häufiger deaktiviert)
Bozho
quelle
Richtig, die dritte Regel ist sehr klar. Befindet sich eine Ausnahme auf sinnvolle Weise in den höheren Ebenen eines Programms? Bedeutet dies, dass APIs im Allgemeinen Ausnahmen auslösen? In welchen Fällen sollte eine Methode auch Ausnahmen von Untermethoden (z. B. von privaten Dienstprogrammmethoden) erneut auslösen?
James P.
Nun, es kommt sehr darauf an. APIs lösen Ausnahmen aus, ja. Aber dann kommt die Wahl zwischen aktiviert und nicht aktiviert.
Bozho
3
Warum die Ausnahme erneut auslösen? Fangen Sie es einfach nicht und geben Sie es an den Aufrufstapel weiter.
Steve Kuo
15

Im Allgemeinen sollte eine Methode eine Ausnahme an ihren Aufrufer senden, wenn sie das zugehörige Problem lokal nicht behandeln kann. Wenn die Methode beispielsweise aus einer Datei mit dem angegebenen Pfad lesen soll, IOExceptionskann sie lokal nicht sinnvoll behandelt werden. Gleiches gilt für ungültige Eingaben. Meine persönliche Entscheidung wäre, eine ungeprüfte Ausnahme wie IllegalArgumentExceptionin diesem Fall auszulösen .

Und es sollte eine Ausnahme von einer aufgerufenen Methode abfangen, wenn:

  • Dies kann lokal behandelt werden (z. B. beim Versuch, eine Eingabezeichenfolge in eine Zahl zu konvertieren, und wenn die Konvertierung fehlschlägt, ist es völlig gültig, stattdessen einen Standardwert zurückzugeben).
  • oder es sollte nicht ausgelöst werden (z. B. wenn die Ausnahme von einer implementierungsspezifischen unteren Ebene stammt, deren Implementierungsdetails für den Aufrufer nicht sichtbar sein sollten - zum Beispiel möchte ich nicht zeigen, dass meine DAOVerwendungen Hibernatefür das Fortbestehen meiner Entitäten verwendet werden Ich fange alle HibernateExceptionslokal ab und konvertiere sie in meine eigenen Ausnahmetypen.
Péter Török
quelle
In Ordnung. Bei einer Neuformulierung wird eine Ausnahme ausgelöst, wenn eine sofortige Lösung nicht möglich ist und "oben" eine gewisse Interaktion erforderlich ist, um zu entscheiden, was zu tun ist. Außerdem würde eine Ausnahme nicht erneut ausgelöst, wenn sie nur eine "Bedeutung" zwischen einer Gruppe von Klassen hat und an ihrer Stelle eine allgemeinere Ausnahme ausgelöst werden sollte, um den Anrufer darüber zu informieren, dass seine Aufmerksamkeit erforderlich ist. Klingt das mehr oder weniger richtig?
James P.
1
@James, mehr oder weniger :-) Wenn Sie unter "Interaktion" das Eingreifen des Benutzers verstehen, wird dies nicht immer benötigt. Anstelle von "allgemeiner" würde ich auch "anders" bevorzugen. Eine benutzerdefinierte ConnectionException ist nicht allgemeiner als die HibernateException.
Péter Török
11

So benutze ich es:

Würfe:

  • Sie möchten nur, dass der Code stoppt, wenn ein Fehler auftritt.
  • Gut mit Methoden, die fehleranfällig sind, wenn bestimmte Voraussetzungen nicht erfüllt sind.

Try-Catch:

  • Wenn Sie möchten, dass sich das Programm mit unterschiedlichen Fehlern unterschiedlich verhält.
  • Großartig, wenn Sie Endbenutzern aussagekräftige Fehler bereitstellen möchten .

Ich kenne viele Leute, die Throws immer benutzen, weil es sauberer ist, aber es gibt bei weitem nicht so viel Kontrolle.

Justian Meyer
quelle
Sie sollten fast NIEMALS die Ausnahmebehandlung für die Programmsteuerung verwenden. Es ist eine schreckliche Praxis.
CheesePls
2
Es gibt auch Try-Catch-Rethrow oder Try-Catch-Wrap-Throw - nur weil Sie die Ausnahme auf sinnvolle Weise behandeln können, heißt das nicht, dass Sie fertig sind. Die Methode sollte das tun, was der Name anzeigt, oder eine Ausnahme auslösen: abstractions-r-us.blogspot.com/2010/06/… . (Schamloser Plug für mein Blog)
Jyoungdev
1
Dies ist eine Frage, die ich mich seit einiger Zeit gefragt habe. Ich denke, dass ich versuche, Try-Catch-Blöcke bei Bedarf mit benutzerdefinierten Ausnahmen zu verwenden. Ausnahme. Aber ich muss sagen, dass ein Wurf im Methodenstub viel sauberer und viel weniger Code ist, den Sie später sortieren müssen, wenn Sie ein Debugging durchführen müssen. Wenn Sie einen Wurf im Methodenstub verwenden, müssen Sie den Fehler in der Methodenkette abfangen. Ich denke, das ist mir nicht sicher. Mit einem Try-Catch können Sie einfach den Try-Catch den Fehler abfangen lassen, ohne ihn an die Methodenkette weitergeben zu müssen. Ich bin mir nicht ganz sicher, aber ich denke
Doug Hauf
So geht es im Allgemeinen, denke ich. Ich weiß, dass beim Lesen von Dateien, bei denen Sie einen try-catch verwenden und dann eine Instanz Ihrer Klasse in einer anderen Klasse deklarieren, die Methode nicht die Ausnahme auslösen muss. Da bin ich mir noch nicht sicher.
Doug Hauf
9

Meine persönliche Faustregel dafür ist einfach:

  • Kann ich sinnvoll damit umgehen (aus dem Kommentar hinzugefügt)? Geben Sie also Code ein try/catch. Mit "Handle" meine ich, den Benutzer informieren / Fehler beheben oder im weiteren Sinne verstehen zu können, wie sich diese Ausnahme auf die Ausführung meines Codes auswirkt.
  • An anderer Stelle wegwerfen

Hinweis: Diese Antwort ist jetzt ein Community-Wiki. Sie können gerne weitere Informationen hinzufügen.

Riduidel
quelle
6
Kann ich damit umgehen in einer sinnvollen Art und Weise .
Nivas
2
Nach welchen Kriterien entscheiden Sie, ob Sie eine Ausnahme lokal behandeln können? Befindet sich dies auf der Ebene, auf der Sie sich tatsächlich um die Ausnahme kümmern und beispielsweise eine Nachricht anzeigen können?
James P.
Es wegzuwerfen ist eine schlechte Idee. Besser ist es, es den Aufrufstapel weiterzuleiten.
Steve Kuo
3

Die Entscheidung, Ihren Methoden eine try-catch- oder eine throw-Klausel hinzuzufügen, hängt davon ab, "wie Sie Ihre Ausnahme behandeln möchten (oder müssen)".

Der Umgang mit einer Ausnahme ist eine weitreichende und alles andere als triviale Frage. Es beinhaltet insbesondere die Entscheidung, wo die Ausnahme behandelt werden soll und welche Aktionen innerhalb des catch-Blocks implementiert werden sollen. In der Tat sollte die Behandlung einer Ausnahme eine globale Entwurfsentscheidung sein.

Bei der Beantwortung Ihrer Fragen gibt es keine Faustregel.

Sie müssen entscheiden, wo Sie Ihre Ausnahme behandeln möchten, und diese Entscheidung ist normalerweise sehr spezifisch für Ihre Domain- und Anwendungsanforderungen.

EijiAdachi
quelle
2

Wenn die Methode, bei der die Ausnahme ausgelöst wurde, über eine ausreichende Menge an Informationen verfügt, um damit umzugehen, sollte sie abfangen und nützliche Informationen darüber generieren, was passiert ist und welche Daten verarbeitet wurden.

Alberto Zaccagni
quelle
Schreiben Sie die Fehlerausnahme immer in eine Logger-Datei oder in die Konsole? Ich habe letzte Nacht darüber nachgedacht, weil Sie im eigentlichen Programm die eigentliche Konsole nicht sehen können, sollten Ihre Fehler also nicht in eine Textdatei gehen. Wie wird e.printStackTrace () gedruckt? Ich gehe beim Debuggen zur Konsole, aber wo kann es sonst hingehen?
Doug Hauf
1

Eine Methode sollte nur dann throwseine Ausnahme bilden, wenn sie angemessene Garantien für den Status des Objekts, alle an die Methode übergebenen Parameter und alle anderen Objekte, auf die die Methode einwirkt, geben kann. Beispielsweise kann eine Methode, die ein Element aus einer Sammlung abrufen soll, von dem der Aufrufer erwartet, dass es darin enthalten ist, throwseine aktivierte Ausnahme darstellen, wenn das Element, von dem erwartet wurde, dass es in der Sammlung vorhanden ist, dies nicht tut. Ein Aufrufer, der diese Ausnahme abfängt, sollte erwarten, dass die Sammlung das betreffende Element nicht enthält.

Beachten Sie, dass Java zwar zulässt, dass geprüfte Ausnahmen durch eine Methode in die Luft sprudeln, die als Auslösen von Ausnahmen der entsprechenden Typen deklariert ist, diese Verwendung jedoch im Allgemeinen als Anti-Pattern betrachtet werden sollte. Stellen Sie sich zum Beispiel vor, dass eine Methode LookAtSky()als aufrufend deklariert FullMoonExceptionist und sie voraussichtlich auslösen wird, wenn der Mond voll ist. Stellen Sie sich weiter vor, dass LookAtSky()Anrufe ExamineJupiter(), die auch als deklariert werden throws FullMoonException. Wenn a FullMoonExceptionvon geworfen ExamineJupiter()wurde und LookAtSky()es nicht auffing und entweder damit umging oder es in einen anderen Ausnahmetyp einwickelte, LookAtSkywürde der aufgerufene Code annehmen, dass die Ausnahme darauf zurückzuführen ist, dass der Erdmond voll ist; es hätte keine Ahnung, dass einer von Jupiters Monden der Schuldige sein könnte.

Ausnahmen, die ein Aufrufer möglicherweise behandeln wird (einschließlich im Wesentlichen aller geprüften Ausnahmen), sollten nur dann durch eine Methode übertragen werden können, wenn die Ausnahme für den Aufrufer der Methode dasselbe bedeutet wie für die aufgerufene Methode. Wenn Code eine Methode aufruft, die als ausgelöste Ausnahme deklariert ist, der Aufrufer jedoch nicht erwartet, dass diese Ausnahme in der Praxis jemals ausgelöst wird (z. B. weil er glaubt, dass es sich um vorab validierte Methodenargumente handelt), sollte die geprüfte Ausnahme abgefangen und umbrochen werden in einem ungeprüften Ausnahmetyp. Wenn der Anrufer nicht erwartet, dass die Ausnahme ausgelöst wird, kann der Anrufer nicht erwarten, dass sie eine bestimmte Bedeutung hat.

Superkatze
quelle
1

Wann was zu verwenden. Ich habe viel darüber gesucht. Es gibt keine feste Regel.

"Als Entwickler müssen jedoch geprüfte Ausnahmen in eine Throws-Klausel der Methode aufgenommen werden. Dies ist erforderlich, damit der Compiler weiß, welche Ausnahmen zu prüfen sind. Konventionell sollten nicht aktivierte Ausnahmen nicht in eine Throws-Klausel aufgenommen werden. Das
Einschließen dieser Ausnahmen wird berücksichtigt Der Compiler behandelt sie als Kommentare und überprüft sie nicht. "

Quelle: SCJP 6 Buch von Kathy Sierra

sofs1
quelle
0

Wenn Sie einen Try-Catch verwenden und die Ausnahme auftritt, werden die verbleibenden Codes weiterhin ausgeführt.

Wenn Sie die Methode zum Auslösen der Ausnahme angeben, wird der Code beim Auftreten der Ausnahme sofort nicht mehr ausgeführt.

Jarkid
quelle
0

Das Try-Catch-Paar wird verwendet, wenn Sie ein benutzerdefiniertes Verhalten bereitstellen möchten, falls eine Ausnahme auftritt ..... mit anderen Worten ... Sie haben eine Lösung für Ihr Problem (Auftreten einer Ausnahme) gemäß Ihren Programmanforderungen .... .

Aber Würfe werden verwendet, wenn Sie keine spezifische Lösung für den Fall des Auftretens von Ausnahmen haben ... Sie möchten einfach keine abnormale Beendigung Ihres Programms erhalten ...

Hoffe es ist richtig :-)

user8148636
quelle