Ich habe gerade eine Frage zu Try-Catch gesehen . Welche Leute (einschließlich Jon Skeet) sagen, dass leere Fangblöcke eine wirklich schlechte Idee sind? Warum das? Gibt es keine Situation, in der ein leerer Fang keine falsche Entwurfsentscheidung ist?
Ich meine zum Beispiel, manchmal möchten Sie zusätzliche Informationen von irgendwoher erhalten (Webservice, Datenbank) und es ist Ihnen wirklich egal, ob Sie diese Informationen erhalten oder nicht. Also versuchst du es zu bekommen und wenn etwas passiert, ist das in Ordnung, ich füge einfach einen "catch (Ausnahme ignoriert) {}" hinzu und das ist alles
exception-handling
try-catch
Samuel Carrijo
quelle
quelle
Antworten:
Normalerweise ist ein leerer Try-Catch eine schlechte Idee, da Sie stillschweigend einen Fehlerzustand verschlucken und dann die Ausführung fortsetzen. Gelegentlich mag dies das Richtige sein, aber oft ist es ein Zeichen dafür, dass ein Entwickler eine Ausnahme gesehen hat, nicht wusste, was er dagegen tun soll, und deshalb einen leeren Haken verwendet hat, um das Problem zum Schweigen zu bringen.
Dies ist das Programmieräquivalent zum Anbringen eines schwarzen Klebebands über einer Motorwarnleuchte.
Ich glaube, wie Sie mit Ausnahmen umgehen, hängt davon ab, auf welcher Ebene der Software Sie arbeiten: Ausnahmen im Regenwald .
quelle
Sie sind im Allgemeinen eine schlechte Idee, da es sich um eine wirklich seltene Erkrankung handelt, bei der ein Fehler (Ausnahmezustand, allgemeiner) ordnungsgemäß ohne jegliche Reaktion behandelt wird. Darüber hinaus sind leere
catch
Blöcke ein gängiges Tool, das von Personen verwendet wird, die die Ausnahme-Engine zur Fehlerprüfung verwenden, um sicherzustellen, dass sie dies präventiv tun sollten.Zu sagen, dass es immer schlecht ist, ist falsch ... das gilt für sehr wenig. Es kann Umstände geben, in denen es Ihnen entweder egal ist, dass ein Fehler aufgetreten ist, oder dass das Vorhandensein des Fehlers irgendwie darauf hinweist, dass Sie sowieso nichts dagegen tun können (z. B. wenn Sie einen vorherigen Fehler in eine Textprotokolldatei schreiben und Sie erhalten eine
IOException
, was bedeutet, dass Sie den neuen Fehler sowieso nicht ausschreiben konnten.quelle
Ich würde die Dinge nicht so weit strecken, dass jemand, der leere Fangblöcke verwendet, ein schlechter Programmierer ist und nicht weiß, was er tut ...
Bei Bedarf verwende ich leere Fangblöcke. Manchmal weiß der Programmierer der Bibliothek, die ich konsumiere, nicht, was er tut, und löst Ausnahmen aus, selbst in Situationen, in denen niemand sie benötigt.
Betrachten Sie zum Beispiel eine http-Serverbibliothek. Es ist mir egal, ob der Server eine Ausnahme auslöst, da der Client die Verbindung getrennt hat und
index.html
nicht gesendet werden konnte.quelle
Es gibt seltene Fälle, in denen dies gerechtfertigt sein kann. In Python sieht man oft diese Art von Konstruktion:
Es kann also in Ordnung sein (abhängig von Ihrer Anwendung), Folgendes zu tun:
In einem kürzlich durchgeführten .NET-Projekt musste ich Code schreiben, um Plugin-DLLs aufzulisten und Klassen zu finden, die eine bestimmte Schnittstelle implementieren. Das relevante Codebit (in VB.NET, sorry) ist:
Obwohl ich selbst in diesem Fall zugeben würde, dass das Protokollieren des Fehlers irgendwo eine Verbesserung wäre.
quelle
Leere Fangblöcke werden normalerweise eingefügt, weil der Codierer nicht wirklich weiß, was sie tun. In meiner Organisation muss ein leerer Fangblock einen Kommentar enthalten, warum es eine gute Idee ist, mit der Ausnahme nichts zu tun.
In einem ähnlichen Zusammenhang wissen die meisten Leute nicht, dass auf einen try {} -Block entweder ein catch {} oder ein finally {} folgen kann, nur einer ist erforderlich.
quelle
Ausnahmen sollten nur ausgelöst werden, wenn es wirklich eine Ausnahme gibt - etwas, das über die Norm hinausgeht. Ein leerer Fangblock sagt im Grunde: "Es passiert etwas Schlimmes, aber es ist mir einfach egal." Das ist eine schlechte Idee.
Wenn Sie die Ausnahme nicht behandeln möchten, lassen Sie sie nach oben übertragen, bis ein Code erreicht ist, der sie verarbeiten kann. Wenn nichts mit der Ausnahme umgehen kann, sollte die Anwendung heruntergefahren werden.
quelle
catch (Exception) {}
ist eine schlechte Idee,catch (SpecificExceptionType) {}
könnte vollkommen in Ordnung sein. Der Programmierer hat die Ausnahme anhand der Typinformationen in der catch-Klausel überprüft.Ich denke, es ist in Ordnung, wenn Sie einen bestimmten Ausnahmetyp abfangen, von dem Sie wissen, dass er nur aus einem bestimmten Grund ausgelöst wird, und Sie erwarten diese Ausnahme und müssen wirklich nichts dagegen tun.
Aber auch in diesem Fall ist möglicherweise eine Debug-Meldung angebracht.
quelle
Per Josh Bloch - Punkt 65: Ausnahmen von effektivem Java nicht ignorieren :
quelle
Ein leerer Fangblock sagt im Wesentlichen: "Ich möchte nicht wissen, welche Fehler ausgelöst werden, ich werde sie einfach ignorieren."
Es ist ähnlich wie bei VB6
On Error Resume Next
, außer dass alles im try-Block, nachdem die Ausnahme ausgelöst wurde, übersprungen wird.Was nicht hilft, wenn dann etwas kaputt geht.
quelle
Dies geht Hand in Hand mit "Verwenden Sie keine Ausnahmen zur Steuerung des Programmflusses" und "Verwenden Sie Ausnahmen nur für außergewöhnliche Umstände". In diesem Fall sollten Ausnahmen nur auftreten, wenn ein Problem vorliegt. Und wenn es ein Problem gibt, möchten Sie nicht stillschweigend scheitern. In den seltenen Anomalien, in denen das Problem nicht behoben werden muss, sollten Sie zumindest die Ausnahme protokollieren, nur für den Fall, dass die Anomalie nicht mehr zu einer Anomalie wird. Das einzige, was schlimmer ist als zu scheitern, ist lautlos zu scheitern.
quelle
Ich denke, ein vollständig leerer Catch-Block ist eine schlechte Idee, da es keine Möglichkeit gibt, darauf zu schließen, dass das Ignorieren der Ausnahme das beabsichtigte Verhalten des Codes war. Es ist nicht unbedingt schlecht, eine Ausnahme zu schlucken und in einigen Fällen false oder null oder einen anderen Wert zurückzugeben. Das .net-Framework verfügt über viele "try" -Methoden, die sich so verhalten. Wenn Sie eine Ausnahme verschlucken, sollten Sie als Faustregel einen Kommentar und eine Protokollanweisung hinzufügen, wenn die Anwendung die Protokollierung unterstützt.
quelle
Denn wenn eine Ausnahme ausgelöst wird , werden Sie sie nie sehen - ein stillschweigendes Versagen ist die schlechteste Option - Sie erhalten ein fehlerhaftes Verhalten und keine Ahnung, wo es passiert. Zumindest eine Protokollnachricht dort setzen! Auch wenn es etwas ist, das niemals passieren kann!
quelle
Leere Fangblöcke sind ein Hinweis darauf, dass ein Programmierer mit einer Ausnahme nicht weiß, was er tun soll. Sie unterdrücken, dass die Ausnahme möglicherweise sprudelt und von einem anderen Try-Block korrekt behandelt wird. Versuchen Sie immer, etwas zu tun, mit der Ausnahme, die Sie fangen.
quelle
Ich finde es am ärgerlichsten, wenn leere catch-Anweisungen dies tun, wenn es ein anderer Programmierer getan hat. Ich meine, wenn Sie Code von jemand anderem debuggen müssen, erschweren leere catch-Anweisungen ein solches Unterfangen, als es sein muss. IMHO catch-Anweisungen sollten immer eine Art Fehlermeldung anzeigen - auch wenn der Fehler nicht behandelt wird, sollte er ihn zumindest erkennen (alt. On nur im Debug-Modus)
quelle
Es ist wahrscheinlich nie das Richtige, weil Sie stillschweigend jede mögliche Ausnahme bestehen. Wenn Sie eine bestimmte Ausnahme erwarten, sollten Sie sie testen und erneut auslösen, wenn dies nicht Ihre Ausnahme ist.
quelle
Im Allgemeinen sollten Sie nur die Ausnahmen abfangen, die Sie tatsächlich behandeln können. Das bedeutet, beim Abfangen von Ausnahmen so genau wie möglich zu sein. Das Abfangen aller Ausnahmen ist selten eine gute Idee und das Ignorieren aller Ausnahmen ist fast immer eine sehr schlechte Idee.
Ich kann mir nur einige Fälle vorstellen, in denen ein leerer Fangblock einen sinnvollen Zweck hat. Wenn eine bestimmte Ausnahme, die Sie abfangen, durch erneutes Ausprobieren der Aktion "behandelt" wird, muss im catch-Block nichts unternommen werden. Es wäre jedoch immer noch eine gute Idee, die Tatsache zu protokollieren, dass die Ausnahme aufgetreten ist.
Ein weiteres Beispiel: CLR 2.0 hat die Behandlung nicht behandelter Ausnahmen im Finalizer-Thread geändert. Vor 2.0 durfte der Prozess dieses Szenario überleben. In der aktuellen CLR wird der Prozess im Falle einer nicht behandelten Ausnahme im Finalizer-Thread beendet.
Denken Sie daran, dass Sie einen Finalizer nur implementieren sollten, wenn Sie wirklich einen benötigen, und selbst dann sollten Sie im Finalizer so wenig wie möglich tun. Aber wenn die Arbeit, die Ihr Finalizer leisten muss, eine Ausnahme auslösen könnte, müssen Sie zwischen dem kleineren von zwei Übeln wählen. Möchten Sie die Anwendung aufgrund der nicht behandelten Ausnahme herunterfahren? Oder möchten Sie in einem mehr oder weniger undefinierten Zustand fortfahren? Zumindest theoretisch kann letzteres in einigen Fällen das kleinere von zwei Übeln sein. In diesem Fall würde der leere Fangblock verhindern, dass der Prozess beendet wird.
quelle
Wenn Sie also Ihrem Beispiel folgen, ist dies in diesem Fall eine schlechte Idee, da Sie alle Ausnahmen abfangen und ignorieren . Wenn Sie nur fangen
EInfoFromIrrelevantSourceNotAvailable
und es ignorieren würden, wäre das in Ordnung, aber Sie sind es nicht. Sie ignorieren auchENetworkIsDown
, was wichtig sein kann oder nicht. Sie ignorierenENetworkCardHasMelted
undEFPUHasDecidedThatOnePlusOneIsSeventeen
, die mit ziemlicher Sicherheit wichtig sind.Ein leerer catch-Block ist kein Problem, wenn er so eingerichtet ist, dass nur Ausnahmen bestimmter Typen abgefangen (und ignoriert) werden, von denen Sie wissen, dass sie unwichtig sind. Die Situationen, in denen es eine gute Idee ist, alle Ausnahmen zu unterdrücken und stillschweigend zu ignorieren , ohne sie zuerst zu untersuchen, um festzustellen, ob sie erwartet / normal / irrelevant sind oder nicht, sind äußerst selten.
quelle
Es gibt Situationen, in denen Sie sie verwenden könnten, aber sie sollten sehr selten sein. Zu den Situationen, in denen ich eine verwenden könnte, gehören:
Ausnahmeprotokollierung; Je nach Kontext möchten Sie möglicherweise stattdessen eine nicht behandelte Ausnahme oder Nachricht.
Das Schleifen technischer Situationen wie Rendering oder Soundverarbeitung oder ein Listbox-Rückruf, bei dem das Verhalten selbst das Problem demonstriert, das Auslösen einer Ausnahme im Weg steht und das Protokollieren der Ausnahme wahrscheinlich nur zu Tausenden von "Fehlgeschlagen an XXX" -Nachrichten führt .
Programme, die nicht fehlschlagen können, obwohl sie zumindest noch etwas protokollieren sollten.
Für die meisten Winforms-Anwendungen habe ich festgestellt, dass es ausreicht, für jede Benutzereingabe eine einzige try-Anweisung zu haben. Ich verwende die folgenden Methoden: (AlertBox ist nur ein schneller MessageBox.Show-Wrapper)
Dann kann jeder Event-Handler Folgendes tun:
oder
Theoretisch könnten Sie TryActionSilently verwenden, das möglicherweise besser zum Rendern von Anrufen geeignet ist, damit eine Ausnahme nicht unendlich viele Nachrichten generiert.
quelle
Wenn Sie nicht wissen, was Sie im catch-Block tun sollen, können Sie diese Ausnahme einfach protokollieren, aber nicht leer lassen.
quelle
Sie sollten niemals einen leeren Fangblock haben. Es ist, als würde man einen Fehler verstecken, von dem man weiß. Zumindest sollten Sie eine Ausnahme in eine Protokolldatei schreiben, um sie später zu überprüfen, wenn Sie unter Zeitdruck stehen.
quelle