it-swarm-eu.dev

Ausnahmeverbreitung: Wann sollte ich Ausnahmen abfangen?

MethodA ruft eine MethodB auf, die wiederum MethodC aufruft.

In Methode B oder Methode C gibt es KEINE Ausnahmebehandlung. In MethodA gibt es jedoch eine Ausnahmebehandlung.

In MethodC tritt eine Ausnahme auf.

Diese Ausnahme sprudelt nun zu MethodA, die sie entsprechend behandelt.

Was ist daran falsch?

Meiner Meinung nach wird ein Aufrufer irgendwann MethodB oder MethodC ausführen, und wenn in diesen Methoden Ausnahmen auftreten, was wird durch die Behandlung von Ausnahmen innerhalb dieser Methoden erreicht, die im Wesentlichen nur ein try/catch/finally-Block statt nur let sind sie sprudeln bis zum Angerufenen?

Die Aussage oder der Konsens bezüglich der Ausnahmebehandlung besteht darin, zu werfen, wenn die Ausführung aus genau diesem Grund nicht fortgesetzt werden kann - eine Ausnahme. Ich verstehe das. Aber warum nicht die Ausnahme weiter oben in der Kette abfangen, anstatt Try/Catch-Blöcke ganz unten zu haben?.

Ich verstehe es, wenn Sie Ressourcen freisetzen müssen. Das ist eine ganz andere Sache.

46
Daniel Frost

Fangen Sie im Allgemeinen keine Ausnahmen ab, es sei denn, Sie wissen, was Sie damit tun sollen. Wenn MethodC eine Ausnahme auslöst, MethodB jedoch keine nützliche Möglichkeit zur Behandlung hat, sollte es der Ausnahme ermöglichen, sich bis zu MethodA zu verbreiten.

Die einzigen Gründe, warum eine Methode einen Fang- und Rückwurfmechanismus haben sollte, sind:

  • Sie möchten eine Ausnahme in eine andere konvertieren, die für den obigen Anrufer aussagekräftiger ist.
  • Sie möchten der Ausnahme zusätzliche Informationen hinzufügen.
  • Sie benötigen eine catch-Klausel, um Ressourcen zu bereinigen, die ohne eine durchgesickert wären.

Andernfalls führt das Abfangen von Ausnahmen auf der falschen Ebene dazu, dass Code stillschweigend fehlschlägt, ohne dem aufrufenden Code (und letztendlich dem Benutzer der Software) ein nützliches Feedback zu geben. Die Alternative, eine Ausnahme abzufangen und sie dann sofort wieder zu werfen, ist sinnlos.

140
Simon B

Was ist daran falsch?

Absolut gar nichts.

Diese Ausnahme sprudelt nun zu MethodA, die sie entsprechend behandelt.

"geht angemessen damit um" ist der wichtige Teil. Das ist der Kern der strukturierten Ausnahmebehandlung.

Wenn Ihr Code mit einer Ausnahme etwas "Nützliches" bewirken kann, versuchen Sie es. Wenn nicht, dann lassen Sie es gut in Ruhe.

. . . Warum nicht die Ausnahme weiter oben in der Kette abfangen, anstatt Try/Catch-Blöcke ganz nach unten zu haben?.

Genau das tun Sie sollten. Wenn Sie Code lesen, der Handler/Rethrower "ganz unten" hat, dann lesen Sie [wahrscheinlich] einen ziemlich schlechten Code.

Leider sehen einige Entwickler Catch-Blöcke nur als "Boiler-Plate" -Code, den sie in jede Methode, die sie schreiben, einfügen (kein Wortspiel beabsichtigt), oft, weil sie die Ausnahmebehandlung nicht wirklich "bekommen" und denken, dass sie etwas hinzufügen müssen dass Ausnahmen nicht "entkommen" und ihr Programm töten.

Ein Teil der Schwierigkeit hier ist, dass meistens der Zeit dieses Problem nicht einmal bemerkt wird, weil Ausnahmen nicht die ganze Zeit ausgelöst werden, sondern wenn sie sind =, das Programm wird sehr viel Zeit und Mühe damit verschwenden, den Aufrufstapel schrittweise zu entfernen, um an einen Ort zu gelangen, der tatsächlich etwas Nützliches mit der Ausnahme tut.

21
Phill W.

Sie müssen zwischen Bibliotheken und Anwendungen unterscheiden.

Bibliotheken können nicht erfasste Ausnahmen frei auslösen

Wenn Sie eine Bibliothek entwerfen, müssen Sie irgendwann darüber nachdenken, was schief gehen kann. Die Parameter können im falschen Bereich liegen oder null, externe Ressourcen sind möglicherweise nicht verfügbar usw.

Ihre Bibliothek hat meistens keine Möglichkeit, mit ihnen vernünftig umzugehen. Die einzig sinnvolle Lösung besteht darin, eine entsprechende Ausnahme auszulösen und den Entwickler der Anwendung damit zu beauftragen.

Anwendungen sollten immer irgendwann Ausnahmen abfangen

Wenn eine Ausnahme abgefangen wird, möchte ich sie entweder als Fehler oder schwerwiegende Fehler kategorisieren. Ein reguläres Fehler bedeutet, dass eine einzelne Operation in meiner Anwendung fehlgeschlagen ist. Beispielsweise konnte ein geöffnetes Dokument nicht gespeichert werden, da das Ziel nicht beschreibbar war. Der einzig sinnvolle Gedanke für die Anwendung besteht darin, den Benutzer darüber zu informieren, dass der Vorgang nicht erfolgreich abgeschlossen werden konnte, lesbare Informationen zum Problem zu geben und den Benutzer dann entscheiden zu lassen, was als nächstes zu tun ist.

A Fatal Error ist ein Fehler, den die Hauptanwendungslogik nicht beheben kann. Wenn beispielsweise der Grafikgerätetreiber in einem Videospiel abstürzt, kann die Anwendung den Benutzer nicht "ordnungsgemäß" informieren. In diesem Fall sollte eine Protokolldatei geschrieben und der Benutzer nach Möglichkeit auf die eine oder andere Weise informiert werden.

Selbst in solch einem schweren Fall sollte die Anwendung diese Ausnahme auf sinnvolle Weise behandeln. Dies kann das Schreiben einer Protokolldatei, das Senden eines Absturzberichts usw. umfassen. Es gibt keinen Grund für die Anwendung, nicht auf die Ausnahme zu reagieren.

8
MechMK1

Was an dem von Ihnen beschriebenen Muster falsch ist, ist, dass Methode A keine Möglichkeit hat, zwischen drei Szenarien zu unterscheiden:

  1. Methode B schlug erwartungsgemäß fehl.

  2. Methode C schlug auf eine Weise fehl, die von Methode B nicht erwartet wurde, aber während Methode B eine Operation ausführte, die sicher abgebrochen werden konnte.

  3. Methode C schlug in einer Weise fehl, die von Methode B nicht erwartet wurde, aber während Methode B eine Operation ausführte, die Dinge in einen angeblich vorübergehenden inkohärenten Zustand versetzte, den B aufgrund des Versagens von C nicht bereinigen konnte.

Die einzige Möglichkeit, wie Methode A diese Szenarien unterscheiden kann, besteht darin, dass die von B ausgelöste Ausnahme Informationen enthält, die für diesen Zweck ausreichen, oder wenn das Abwickeln des Stapels für Methode B dazu führt, dass das Objekt in einem explizit ungültig gemacht wird Zustand. Leider machen die meisten Ausnahme-Frameworks beide Muster umständlich und zwingen Programmierer, "weniger böse" Entwurfsentscheidungen zu treffen.

0
supercat