Wann ist es in Ordnung, eine RuntimeException abzufangen?

69

In einem kürzlich durchgeführten Projekt habe ich empfohlen, eine RuntimeException in einem Test-Harness-Code abzufangen und zu protokollieren. Der Code verarbeitet eine Reihe von Eingaben aus einer Datenbank, und ich möchte nicht, dass der Test aufgrund eines Fehlers einer Eingabe (Nullwerte, unzulässige Argumente usw.) gestoppt wird. Unnötig zu erwähnen, dass mein Vorschlag eine leidenschaftliche Diskussion auslöste.

Ist es akzeptabel, irgendeine Art von RuntimeException zu fangen? Wenn ja, in welchen anderen Szenarien ist es in Ordnung, RuntimeExceptions abzufangen?

VDev
quelle

Antworten:

100

Sie fangen RuntimeExceptionaus dem gleichen Grund, aus dem Sie eine Ausnahme machen: Sie planen, etwas damit zu tun. Vielleicht können Sie korrigieren, was die Ausnahme verursacht hat. Vielleicht möchten Sie einfach mit einem anderen Ausnahmetyp erneut werfen.

Das Abfangen und Ignorieren von Ausnahmen ist jedoch eine äußerst schlechte Praxis.

kdgregory
quelle
3
macht durchaus Sinn, hätte auf die Grundlagen zurückgreifen sollen. Oft sind Muster so in Stein gemeißelt, dass Entwickler sie eher als Dogma betrachten. Mir wurde immer gesagt, dass RuntimeExceptions das Ergebnis von a) Programmierfehlern b) katastrophalen Fehlern sind, von denen man sich nicht erholen kann. In Fall (a) möchten Sie sicherstellen, dass alles repariert ist, bevor ein Produkt live geht und "nie" auftreten sollte. In Fall (b) sollte der Benutzer sehen, dass eine bereinigte Nachricht absolut sinnvoll ist, um sie zu erfassen und zu verarbeiten. Jetzt frage ich mich, warum wir überhaupt RuntimeExceptions brauchen, vielleicht ein Thema für eine andere Diskussion ;-)
VDev
1
Heh, ich denke, es ist eher ein Grund, alle Ausnahmen zu Laufzeitausnahmen zu machen . Es gibt viele Programmierer, die geprüfte Ausnahmen abfangen und ignorieren, nur um sie verschwinden zu lassen.
kdgregory
1
@LokiAstari nicht fangen UND erneut werfen; Das Debuggen ist verwirrend, da dieselbe Ausnahme möglicherweise zweimal auftritt. Protokollieren und Anzeigen der Ausnahmemeldung ist akzeptabel, oder Protokollverfolgung und erneutes Auslösen der Ausnahme. Oder nicht loggen und neu werfen.
Ben
35

Wenn Sie eine RuntimeException nicht korrigieren können, möchten Sie sie nicht abfangen ...

... nur aus Entwicklersicht wahr ....

Sie müssen alle Ausnahmen abfangen, bevor sie die Benutzeroberfläche erreichen und Ihren Benutzer traurig machen . Dies bedeutet, dass Sie auf der "höchsten Ebene" alles fangen möchten, was weiter unten passiert ist. Dann können Sie den Benutzer über ein Problem informieren und gleichzeitig Maßnahmen ergreifen, um die Entwickler zu informieren, z. B. das Versenden von Alarm-Mails oder was auch immer ...

Grundsätzlich handelt es sich um einen Daten- / Programmierfehler, der nicht vorhergesehen werden konnte. Sie möchten daher zukünftige Versionen der Software verbessern und gleichzeitig den Benutzer bei der Hand nehmen und kontrolliert weitermachen ...

raoulsson
quelle
15

RuntimeException soll für Programmiererfehler verwendet werden. Als solches sollte es niemals gefangen werden. Es gibt einige Fälle, in denen es sein sollte:

  1. Sie rufen Code von einem Drittanbieter auf, bei dem Sie keine Kontrolle darüber haben, wann dieser eine Ausnahme auslöst. Ich würde argumentieren, dass Sie dies von Fall zu Fall tun und die Verwendung des Codes von Drittanbietern in Ihre eigenen Klassen einschließen sollten, damit Sie Nicht-Laufzeit-Ausnahmen zurückgeben können.

  2. Ihr Programm kann nicht abstürzen und dem Benutzer eine Stapelverfolgung hinterlassen. In diesem Fall sollte es sich um Haupt- und um Threads und Ereignisbehandlungscode handeln. Das Programm sollte wahrscheinlich beendet werden, wenn eine solche Ausnahme ebenfalls auftritt.

In Ihrem speziellen Fall müsste ich mich fragen, warum in den Tests RuntimeExceptions auftreten - Sie sollten sie beheben, anstatt sie zu umgehen.

Sie sollten also sicherstellen, dass Ihr Code nur dann RuntimeExceptions auslöst, wenn Sie das Programm beenden möchten. Sie sollten RuntimeExceptions nur abfangen, wenn Sie es protokollieren und beenden möchten. Dies steht im Einklang mit der Absicht von RuntimeExceptions.

Sie können sich diese Diskussion aus anderen Gründen ansehen , die die Leute angeben ... Ich persönlich habe jedoch keinen zwingenden Grund in den Antworten gefunden.

TofuBeer
quelle
1
Oder 3. Sie können das Problem auf mittlerer Ebene beheben oder umgehen, bevor es den Stapelbaum verlässt
tar
7

Vor Jahren haben wir ein Steuerungssystem-Framework geschrieben, und die Agent-Objekte haben Laufzeitausnahmen abgefangen, sie protokolliert, wenn sie konnten, und wurden fortgesetzt.

Ja, wir haben Laufzeitausnahmen einschließlich OutOfMemory in unserem Framework-Code abgefangen (und einen GC erzwungen, und es ist überraschend, wie gut das auch ziemlich undichten Code ausgeführt hat.) Wir hatten Code, der sehr mathematische Dinge in der realen Welt ausführte. und von Zeit zu Zeit kam eine Not-A-Nummer aufgrund winziger Rundungsfehler herein und es kam auch damit klar.

Also im Framework / "darf nicht beenden" Code denke ich, dass es gerechtfertigt sein kann. Und wenn es funktioniert, ist es ziemlich cool.

Der Code war ziemlich solide, aber es lief Hardware, und Hardware neigt manchmal dazu, verrückte Antworten zu geben.

Es wurde entwickelt, um monatelang ohne menschliches Eingreifen zu laufen. In unseren Tests hat es sehr gut funktioniert.

Als Teil des Fehlerbehebungscodes kann das gesamte Gebäude neu gestartet werden, indem die USV in N Minuten ausgeschaltet und in M ​​Minuten eingeschaltet werden kann.

Manchmal müssen Hardwarefehler aus- und wieder eingeschaltet werden :)

Wenn ich mich recht erinnere, war der letzte Ausweg nach einem erfolglosen Aus- und Einschalten das Senden einer E-Mail an die Eigentümer mit der Aufschrift "Ich habe versucht, mich selbst zu reparieren und ich kann nicht; das Problem liegt im Subsystem XYZ" und einem Link zum Aufrufen eines Supports Rufen Sie uns zurück.

Leider wurde das Projekt eingemacht, bevor es sich selbst bewusst werden konnte :)>

Tim Williscroft
quelle
plus eins für die Erwähnung von "selbstbewusst" ... nur wenn es der 4. August 1997 war.
shrini1000
7

In meinem Code werden 99% meiner Ausnahmen von runtime_exception abgeleitet.

Die Gründe, warum ich Ausnahmen fange, sind:

  • Catch Log und Fix Problem.
  • Catch Log und Generieren Sie eine spezifischere Ausnahme und werfen Sie
  • Catch Log und erneut werfen .
  • Catch Log and Kill-Vorgang (Ausnahme verwerfen)
    • Vom Benutzer / Anforderung initiierte Aktion schlägt fehl.
      Zum Beispiel ein HTTP-Request-Handler. Ich würde lieber die angeforderte Operation sterben lassen, als den Service herunterzufahren. (Obwohl der Handler vorzugsweise genug Sinn hat, um einen 500-Fehlercode zurückzugeben.)
    • Testfall mit Ausnahme bestanden / fehlgeschlagen.
    • Alle Ausnahmen nicht im Haupt-Thread.
      Das Zulassen, dass Ausnahmen einem Thread entkommen, ist normalerweise schlecht dokumentiert, führt jedoch normalerweise zum Beenden des Programms (ohne Abwickeln des Stapels).
Martin York
quelle
4

Persönlich wurde mir immer gesagt, dass Sie alle RuntimeExceptions abfangen möchten. Sie möchten jedoch auch etwas gegen die Ausnahme unternehmen , z. B. eine Ausfallsicherheit ausführen oder den Benutzer möglicherweise nur über das Auftreten eines Fehlers informieren.

Das letzte Java-Projekt, an dem ich gearbeitet habe, hatte einen ähnlichen Ansatz. Zumindest haben wir die Ausnahme protokolliert, damit wir, wenn ein Benutzer anruft und sich über einen Fehler beschwert, genau herausfinden können, was passiert ist, und sehen können, wo der Fehler aufgetreten ist.

Edit 1: Wie kdgregory sagte, sind Fangen und Ignorieren zwei verschiedene Dinge, im Allgemeinen sind die Leute gegen Letzteres :-)

Topher Fangio
quelle
3

Wir alle wissen, dass geprüfte Ausnahmen und RuntimeExceptionssind die beiden Kategorien von Ausnahmen. Es wird immer empfohlen, die aktivierten Ausnahmen zu behandeln (entweder zu versuchen oder zu werfen), da dies die Programmierbedingungen sind, unter denen der Programmierer leider nichts alleine tun kann. Als FileNotFoundExceptionob es nicht der Programmierer ist, der Dateien auf das Laufwerk des Benutzers legt, wenn das Programm tatsächlich versucht, die Datei zu lesen, die 1.txtauf dem f:\Benutzer mit den folgenden Anweisungen vorhanden sein soll:

File f11 = new File("f:\\1.txt");
FileInputStream fos = new FileInputStream(f11);

Wenn die Datei gefunden wird, ist alles in Ordnung, aber im anderen Fall, wenn die Datei nicht gefunden wird, stürzt das Programm mit dem Fehler 0 des Benutzers ab. In diesem Szenario hat der Programmierer nichts falsch gemacht. Dies kann eine aktivierte Ausnahme sein, die abgefangen werden muss, damit das Programm weiter ausgeführt werden kann.

Lassen Sie mich auch das zweite Szenario erklären, mit dem das Konzept von RuntimeExceptionklar wird. Betrachten Sie folgenden Code:

int a = {1,2,3,4,5};
System.out.println(a[9]);

Dies ist eine schlechte Codierung, die die erzeugt ArrayIndexOutOfBoundsException. Welches ist ein Beispiel für RuntimeException. Daher sollte der Programmierer die Ausnahme nicht wirklich behandeln, das Programm abstürzen lassen und später die Logik korrigieren.

Sunya
quelle
3

Sie fangen, RuntimeExceptionwenn Sie es verarbeiten möchten. Vielleicht möchten Sie es als eine andere Ausnahme erneut auslösen oder in einer Datei oder Datenbank protokollieren, oder Sie möchten ein Ausnahmeflag im Rückgabetyp usw. aktivieren.

fastcodejava
quelle
1

Sie fangen RuntimeExceptions ab (in jeder Sprache: unerwartete Ausnahmen / "alle" Ausnahmen), wenn Ihr Programm mehrere Unteraufgaben ausführt, und es ist sinnvoll, alle möglichen Aufgaben abzuschließen, anstatt bei der ersten unerwarteten Situation anzuhalten. Eine Testsuite ist eine gute Situation, um dies zu tun - Sie möchten wissen, welche von allen , nicht nur der erste Test nicht bestanden die Tests. Das Hauptmerkmal ist, dass jeder Test unabhängig von allen anderen ist - es spielt keine Rolle, ob ein vorheriger Test nicht ausgeführt wird, da die Reihenfolge ohnehin nicht von Bedeutung ist.

Eine andere häufige Situation ist ein Server; Sie möchten nicht herunterfahren, nur weil eine Anforderung auf eine Weise fehlerhaft war, die Sie nicht erwartet hatten. (Es sei denn, es ist wirklich sehr wichtig, die Wahrscheinlichkeit eines inkonsistenten Zustands zu minimieren.)

In jeder dieser Situationen ist es angemessen, die Ausnahme zu protokollieren / zu melden und mit den verbleibenden Aufgaben fortzufahren.

Man könnte vage auf jede Ausnahme verallgemeinern: Es ist „angemessen“, eine Ausnahme genau dann abzufangen, wenn nach dem Abfangen etwas Sinnvolles zu tun ist: wie Ihr Programm fortgesetzt werden soll .

Kevin Reid
quelle
0

Wenn von einem Client vernünftigerweise erwartet werden kann, dass er sich von einer Ausnahme erholt, machen Sie ihn zu einer aktivierten Ausnahme.

Wenn ein Client nichts tun kann, um die Ausnahme wiederherzustellen, machen Sie es zu einer nicht aktivierten Ausnahme.

Hier ist die Grundlinie.

Aus Java Docs . Bitte lesen Sie diese ungeprüften Ausnahmen - Die Kontroverse

VdeX
quelle