Frage

Bei der Analyse von Legacy-Code mit FXCop kam mir der Gedanke, ob es wirklich so schlimm ist, einen allgemeinen Ausnahmefehler innerhalb eines Try-Blocks abzufangen, oder ob man nach einer bestimmten Ausnahme suchen sollte.Gedanken bitte auf einer Postkarte.

War es hilfreich?

Lösung

Offensichtlich ist dies eine dieser Fragen, auf die die einzige wirkliche Antwort lautet: „Es kommt darauf an.“

Die Hauptsache hängt davon ab, wo Sie die Ausnahme abfangen.Im Allgemeinen sollten Bibliotheken beim Abfangen von Ausnahmen konservativer vorgehen, während sie auf der obersten Ebene Ihres Programms (z. B.in Ihrer Hauptmethode oder oben in der Aktionsmethode in einem Controller usw.) können Sie großzügiger mit dem umgehen, was Sie fangen.

Der Grund hierfür liegt darin, dass z.B.Sie möchten nicht alle Ausnahmen in einer Bibliothek abfangen, da Sie möglicherweise Probleme maskieren, die nichts mit Ihrer Bibliothek zu tun haben, z. B. „OutOfMemoryException“, bei dem Sie eigentlich lieber Blasen bilden würden, damit der Benutzer benachrichtigt werden kann usw.Wenn Sie andererseits über das Abfangen von Ausnahmen innerhalb Ihrer main()-Methode sprechen, die die Ausnahme abfängt, anzeigt und dann beendet ...Nun, hier kann man wahrscheinlich fast jede Ausnahme treffen.

Die wichtigste Regel zum Abfangen aller Ausnahmen ist, dass Sie niemals alle Ausnahmen stillschweigend schlucken sollten ...z.B.so etwas in Java:

try { 
    something(); 
} catch (Exception ex) {}

oder dies in Python:

try:
    something()
except:
    pass

Denn dies können einige der am schwierigsten aufzuspürenden Probleme sein.

Als Faustregel gilt, dass Sie nur Ausnahmen abfangen sollten, mit denen Sie selbst richtig umgehen können.Wenn Sie die Ausnahme nicht vollständig behandeln können, sollten Sie sie an jemanden weitergeben lassen, der dies kann.

Andere Tipps

Es sei denn, Sie protokollieren und bereinigen Code im Frontend Ihrer Anwendung, dann halte ich es für schlecht, alle Ausnahmen abzufangen.

Meine grundlegende Faustregel ist, alle erwarteten Ausnahmen abzufangen, und alles andere ist ein Fehler.

Wenn Sie alles erfassen und weiterfahren, ist das ein bisschen so, als würden Sie ein Heftpflaster über die Warnleuchte auf dem Armaturenbrett Ihres Autos kleben.Sie können es nicht mehr sehen, aber das bedeutet nicht, dass alles in Ordnung ist.

Ja!(außer ganz oben in Ihrer Bewerbung)

Indem Sie eine Ausnahme abfangen und die Fortsetzung der Codeausführung zulassen, geben Sie an, dass Sie wissen, wie Sie mit einem bestimmten Problem umgehen und es umgehen oder beheben können.Sie behaupten, dass dies der Fall ist eine wiederherstellbare Situation.Das Abfangen einer Ausnahme oder SystemException bedeutet, dass Sie Probleme wie E/A-Fehler, Netzwerkfehler, Fehler wegen unzureichendem Arbeitsspeicher, Fehler wegen fehlendem Code, Nullzeiger-Dereferenzierung und Ähnliches abfangen.Es ist eine Lüge zu behaupten, man könne damit umgehen.

In einer gut organisierten Anwendung sollten diese nicht behebbaren Probleme weit oben im Stapel behandelt werden.

Darüber hinaus möchten Sie nicht, dass Ihre Funktion bei der Weiterentwicklung des Codes eine neue Ausnahme abfängt, die hinzugefügt wird in der Zukunft zu einer aufgerufenen Methode.

Meiner Meinung nach sollten Sie alle Ausnahmen abfangen erwarten, aber diese Regel gilt für alles außer Ihrer Schnittstellenlogik.Im gesamten Aufrufstapel sollten Sie wahrscheinlich eine Möglichkeit schaffen, alle Ausnahmen abzufangen, etwas zu protokollieren/Benutzer-Feedback zu geben und, falls erforderlich und möglich, ordnungsgemäß herunterzufahren.

Nichts ist schlimmer als eine Anwendung, die abstürzt und ein benutzerfreundlicher Stacktrace auf dem Bildschirm angezeigt wird.Dies gewährt nicht nur (vielleicht unerwünschte) Einblicke in Ihren Code, sondern verwirrt auch Ihren Endbenutzer und schreckt ihn manchmal sogar ab, sich einer Konkurrenzanwendung zuzuwenden.

Es gab viele philosophische Diskussionen (eher Auseinandersetzungen) zu diesem Thema.Ich persönlich glaube, das Schlimmste, was man tun kann, ist, Ausnahmen zu schlucken.Das nächstschlimmste Problem besteht darin, zuzulassen, dass eine Ausnahme an die Oberfläche sprudelt, wo der Benutzer einen hässlichen Bildschirm voller technischem Hokuspokus erhält.

Ich denke, der Punkt ist zweierlei.

Erstens: Wenn Sie nicht wissen, welche Ausnahme aufgetreten ist, wie können Sie hoffen, sie zu beheben?Wenn Sie davon ausgehen, dass ein Benutzer möglicherweise einen Dateinamen falsch eingibt, können Sie mit einer FileNotFoundException rechnen und den Benutzer auffordern, es erneut zu versuchen.Wenn derselbe Code eine NullReferenceException erzeugen würde und Sie den Benutzer einfach dazu auffordern würden, es noch einmal zu versuchen, wüsste er nicht, was passiert ist.

Zweitens konzentrieren sich die FxCop-Richtlinien auf Bibliotheks-/Framework-Code – nicht alle Regeln sind so konzipiert, dass sie auf EXE- oder ASP.Net-Websites anwendbar sind.Daher ist es eine gute Sache, einen globalen Ausnahmehandler zu haben, der alle Ausnahmen protokolliert und die Anwendung ordnungsgemäß beendet.

Das Problem beim Abfangen aller Ausnahmen besteht darin, dass Sie möglicherweise Ausnahmen abfangen, die Sie nicht erwarten oder die Sie sogar sollten nicht fängig sein.Tatsache ist, dass eine Ausnahme jeglicher Art darauf hinweist, dass etwas schief gelaufen ist, und Sie müssen das Problem beheben, bevor Sie fortfahren. Andernfalls kann es zu Problemen mit der Datenintegrität und anderen Fehlern kommen, die nicht so einfach aufzuspüren sind.

Um ein Beispiel zu nennen: In einem Projekt habe ich einen Ausnahmetyp namens CriticalException implementiert.Dies weist auf einen Fehlerzustand hin, der ein Eingreifen der Entwickler und/oder des Verwaltungspersonals erfordert. Andernfalls erhalten Kunden falsche Rechnungen oder es kann zu anderen Datenintegritätsproblemen kommen.Es kann auch in anderen ähnlichen Fällen verwendet werden, wenn die bloße Protokollierung der Ausnahme nicht ausreicht und eine E-Mail-Benachrichtigung gesendet werden muss.

Ein anderer Entwickler, der das Konzept von Ausnahmen nicht richtig verstand, hat dann Code, der diese Ausnahme möglicherweise auslösen könnte, in einen generischen try...catch-Block verpackt, der alle Ausnahmen verwirft.Zum Glück habe ich es entdeckt, aber es hätte zu ernsthaften Problemen führen können, insbesondere da sich herausstellte, dass der „sehr ungewöhnliche“ Eckfall, den es abfangen sollte, viel häufiger vorkam, als ich erwartet hatte.

Im Allgemeinen ist es also schlecht, generische Ausnahmen abzufangen, es sei denn, Sie sind zu 100 % sicher, dass Sie es wissen genau welche Arten von Ausnahmen unter welchen Umständen ausgelöst werden.Lassen Sie sie im Zweifelsfall stattdessen zum Ausnahmebehandler der obersten Ebene aufsteigen.

Eine ähnliche Regel besteht hier darin, niemals Ausnahmen vom Typ System.Exception auszulösen.Möglicherweise möchten Sie (oder ein anderer Entwickler) Ihre spezifische Ausnahme weiter oben im Aufrufstapel abfangen und andere durchlassen.

(Es gibt jedoch einen Punkt zu beachten.Wenn in .NET 2.0 ein Thread auf nicht abgefangene Ausnahmen stößt, entlädt er Ihre gesamte App-Domäne.Daher sollten Sie den Hauptteil eines Threads in einen generischen try...catch-Block einschließen und alle dort abgefangenen Ausnahmen an Ihren globalen Ausnahmebehandlungscode übergeben.)

Nun, ich sehe keinen Unterschied zwischen dem Abfangen einer allgemeinen oder einer bestimmten Ausnahme, außer dass man bei mehreren Catch-Blöcken unterschiedlich reagieren kann, je nachdem, um welche Ausnahme es sich handelt.

Zusammenfassend lässt sich sagen, dass Sie beides fangen werden IOException Und NullPointerException mit einem Generikum Exception, aber die Art und Weise, wie Ihr Programm reagieren sollte, ist wahrscheinlich anders.

Ich würde gerne den Advokaten des Teufels spielen, wenn es darum geht, eine Ausnahme abzufangen, sie zu protokollieren und erneut auszulösen.Dies kann erforderlich sein, wenn Sie sich beispielsweise irgendwo im Code befinden und eine unerwartete Ausnahme auftritt. Sie können diese abfangen, aussagekräftige Statusinformationen protokollieren, die in einem einfachen Stack-Trace nicht verfügbar wären, und sie dann an höhere Ebenen weitergeben bewältigen.

Es gibt zwei völlig unterschiedliche Anwendungsfälle.Die erste ist die, über die die meisten Leute nachdenken: Einen Vorgang, der eine geprüfte Ausnahme erfordert, mit einem Try/Catch zu umgehen.Dies sollte auf keinen Fall ein Allheilmittel sein.

Die zweite besteht jedoch darin, zu verhindern, dass Ihr Programm abstürzt, wenn es weiterlaufen könnte.Diese Fälle sind:

  • Der Anfang aller Threads (Standardmäßig verschwinden Ausnahmen spurlos!)
  • Innerhalb einer Hauptverarbeitungsschleife, von der Sie erwarten, dass sie niemals beendet wird
  • Innerhalb einer Schleife wird eine Liste von Objekten verarbeitet, bei denen ein Fehler andere nicht stoppen sollte
  • Oben im „Haupt“-Thread – Sie können hier einen Absturz kontrollieren, indem Sie beispielsweise ein paar Daten auf stdout ausgeben, wenn Ihnen der Arbeitsspeicher ausgeht.
  • Wenn Sie einen „Runner“ haben, der Code ausführt (z. B. wenn Ihnen jemand einen Listener hinzufügt und Sie den Listener aufrufen), sollten Sie beim Ausführen des Codes eine Ausnahme abfangen, um das Problem zu protokollieren und andere Listener weiterhin benachrichtigen zu können.

In diesen Fällen möchten Sie IMMER eine Ausnahme (manchmal vielleicht sogar auslösbar) abfangen, um Programmier-/unerwartete Fehler abzufangen, sie zu protokollieren und fortzufahren.

Ich denke, eine gute Richtlinie besteht darin, nur bestimmte Ausnahmen innerhalb eines Frameworks abzufangen (damit die Hostanwendung Randfälle wie das Auffüllen der Festplatte usw. bewältigen kann), aber ich verstehe nicht, warum wir nicht alle abfangen können sollten Ausnahmen von unserem Anwendungscode.Es gibt ganz einfach Zeiten, in denen Sie nicht möchten, dass die App abstürzt, egal, was schief gehen könnte.

In den meisten Fällen ist das Abfangen einer allgemeinen Ausnahme nicht erforderlich.Natürlich gibt es Situationen, in denen man keine Wahl hat, aber in diesem Fall denke ich, dass es besser ist, zu prüfen, warum man es fangen muss.Vielleicht stimmt etwas mit Ihrem Design nicht.

Wenn ich eine allgemeine Ausnahme sehe, kommt es mir so vor, als würde man eine Stange Dynamit in ein brennendes Gebäude halten und den Zünder löschen.Für eine kurze Zeit hilft es, aber nach einer Weile explodiert das Dynamit trotzdem.

Natürlich kann es Situationen geben, in denen das Abfangen einer allgemeinen Ausnahme erforderlich ist, jedoch nur zu Debugzwecken.Fehler und Bugs sollten behoben und nicht versteckt werden.

Bei meiner IabManager-Klasse, die ich mit In-App-Abrechnung verwendet habe (aus dem TrivialDrive-Beispiel online), ist mir aufgefallen, dass es manchmal zu vielen Ausnahmen kam.Es kam zu einem Punkt, an dem es unvorhersehbar war.

Mir wurde klar, dass ich auf der sicheren Seite wäre, solange ich den Versuch einstellte, ein In-App-Produkt zu konsumieren, nachdem eine Ausnahme aufgetreten war, bei der die meisten Ausnahmen auftreten würden (beim Konsumieren im Gegensatz zum Kaufen).

Ich habe einfach alle Ausnahmen in eine allgemeine Ausnahme geändert und muss mir jetzt keine Sorgen mehr machen, dass weitere zufällige, unvorhersehbare Ausnahmen ausgelöst werden.

Vor:

    catch (final RemoteException exc)
    {
        exc.printStackTrace();
    }
    catch (final IntentSender.SendIntentException exc)
    {
        exc.printStackTrace();
    }
    catch (final IabHelper.IabAsyncInProgressException exc)
    {
        exc.printStackTrace();
    }
    catch (final NullPointerException exc)
    {
        exc.printStackTrace();
    }
    catch (final IllegalStateException exc)
    {
        exc.printStackTrace();
    }

Nach:

    catch (final Exception exc)
    {
        exc.printStackTrace();
    }

Unpopuläre Meinung:Nicht wirklich.

Erfassen Sie alle Fehler, die Sie sinnvoll beheben können.Manchmal sind das alle.

Meiner Erfahrung nach ist es wichtiger Wo Die Ausnahme kam von der Ausnahme, die tatsächlich ausgelöst wurde.Wenn Sie Ihre Ausnahmen auf engstem Raum halten, werden Sie in der Regel nichts verschlucken, was sonst nützlich wäre.Bei den meisten Informationen, die in der Art eines Fehlers kodiert sind, handelt es sich um Zusatzinformationen, die Sie im Allgemeinen effektiv abfangen alle von ihnen sowieso (aber Sie müssen jetzt die API-Dokumente nachschlagen, um den gesamten Satz möglicher Ausnahmen zu erhalten).

Denken Sie daran, dass es einige Ausnahmen gibt, die in fast allen Fällen nach oben sprudeln sollten, wie zum Beispiel die von Python KeyboardInterrupt Und SystemExit.Zum Glück für Python werden diese in einem separaten Zweig der Ausnahmehierarchie gespeichert, sodass Sie sie durch Abfangen aufsprudeln lassen können Exception.Eine gut gestaltete Ausnahmehierarchie macht solche Dinge wirklich einfach.

Das Abfangen allgemeiner Ausnahmen führt hauptsächlich dann zu ernsthaften Problemen, wenn es um Ressourcen geht, die bereinigt werden müssen (vielleicht in einem finally -Klausel), da ein Catch-All-Handler so etwas leicht übersehen kann.Glücklicherweise ist dies für Sprachen mit kein wirkliches Problem defer, Konstrukte wie Pythons with, oder RAII in C++ und Rust.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top