Ist es nicht eine gute Praxis, Laufzeitausnahmen im Code zu behandeln?

11

Ich arbeite an einer Java-Anwendung und sehe, dass Laufzeitausnahmen an vielen Stellen behandelt werden. Beispielsweise,

try {
    // do something
} catch(NullPointerException e) {
    return null;
}

Meine Frage ist, wann es eine gute Praxis ist, Laufzeitausnahmen zu behandeln. Wann sollten Ausnahmen unbehandelt bleiben?

Vinoth Kumar CM
quelle
7
-1: Es gibt keine einzige Antwort auf eine so breite und vage Frage. Es ist unmöglich, eine einzige Antwort auf eine so unkonzentrierte Frage zu geben. Diese Frage ist schrecklich. Bitte geben Sie konkrete Beispiele dafür, wo Sie Zweifel haben.
S.Lott
@ S.Lott Ich bin in diesem Fall nicht einverstanden, da es anscheinend eine Untergruppe von Programmierern gibt, die es im Kopf haben, dass dies ohne "gute" Rationalität der Fall ist.
SoylentGray
2
@Chad: "Dies ist der Fall ohne" gute "Rationalität". Das könnte stimmen. Aber die einzig mögliche Antwort muss "es kommt darauf an" sein. Daher scheint die Frage fehlerhaft zu sein.
S.Lott

Antworten:

18

Es hängt davon ab, ob.

Zum Beispiel Integer#parseIntwirft NumberFormatException(was eine RTE ist), wenn die bereitgestellte Zeichenfolge nicht analysiert werden kann. Aber sicher möchten Sie nicht, dass Ihre App abstürzt, nur weil der Benutzer "x" in ein Textfeld geschrieben hat, das für ganze Zahlen gedacht ist? Und woher wissen Sie, ob die Zeichenfolge analysiert werden kann, es sei denn, Sie versuchen zuerst, sie zu analysieren? In diesem Fall ist die RTE also nur ein Fehlersignal, das eine Fehlermeldung verursachen sollte. Man könnte argumentieren , dass es sollte eine geprüfte Ausnahme sein, aber was kann man tun - es ist nicht.

Joonas Pulakka
quelle
2
Ich stimme "Es kommt darauf an" an, aber Ihr Analysebeispiel scheint eher ein Fall von schlechtem API-Design zu sein. Integer#parseIntsollte wirklich ein Maybe<Integer>stattdessen zurückgeben und überhaupt keine Ausnahme auslösen.
Jörg W Mittag
3
@ Jörg W Mittag: Ich stimme zu, dass es schlechtes API-Design ist, aber es ist die reale Welt, mit der wir uns befassen müssen. Wie man mit Wurf- / Rückgabewerten richtig umgeht, hängt davon ab, wie die Welt tatsächlich funktioniert und nicht davon, wie sie optimal funktionieren sollte :-)
Joonas Pulakka
Der Punkt hier ist, dass Sie etwas Sinnvolles für eine erwartete Bedingung tun können (Benutzereingabe nicht Ganzzahl). Nur NPE zu schlucken ist ein schlechter Stil und vertuscht nur vorhandene Programmierfehler.
Jürgen Strobel
7

NullPointerExceptions sind normalerweise das Zeichen einer fehlenden Nullprüfung. Anstatt es so abzufangen, sollten Sie die entsprechende Nullprüfung hinzufügen, um sicherzustellen, dass die Ausnahme nicht ausgelöst wird.

Manchmal ist es jedoch angebracht, RunTimeExceptions zu behandeln. Zum Beispiel, wenn Sie den Code nicht ändern können, um die Nullprüfung an der entsprechenden Stelle hinzuzufügen, oder wenn die Ausnahme etwas anderes als eine NullPointerException ist.

Ihr Beispiel für den Umgang mit Ausnahmen ist schrecklich. Auf diese Weise verlieren Sie die Stapelverfolgung und genaue Informationen zum Problem. Und Sie lösen es tatsächlich nicht, da Sie wahrscheinlich eine weitere NullPointerException an einem anderen Ort auslösen und irreführende Informationen darüber erhalten, was passiert ist und wie es gelöst werden kann.

deadalnix
quelle
1
Ich möchte hinzufügen, dass eine Nullprüfung eine bessere Entscheidung in Bezug auf die Leistung ist.
Mahmoud Hossam
... dennoch, wenn Sie Dutzende von Zuweisungen vornehmen, die an einer Stelle "niemals fehlschlagen" sollten, kann das Hinzufügen von Nullprüfungen für jede von ihnen den Code auf lächerliche Weise verschleiern. Eine Sammelausnahme (die die Situation nicht nur angemessen handhabt return null;) ist eine bessere Lösung.
SF.
Sie verwechseln Java wahrscheinlich mit etwas anderem (z. B. C ++). Wenn eine Zuordnung fehlschlägt, erhalten Sie einen OutOfMemoryError oder ähnliches, niemals einen Nullzeiger. Wenn Sie eine Null-Rückgabe anstelle einer Ausnahme ausblenden, wird der Fehler ausgeblendet, der darauf wartet, dass der Code an einer anderen Stelle explodiert.
Deadalnix
newwirft std::bad_allocin C ++.
R. Martinho Fernandes
Angenommen, der neue Operator ist nicht überlastet, was allgemein üblich ist. In C ++ kann alles passieren;) Aber OK, sagen wir mal Cs Malloc. Der wichtige Punkt war, dass man das in Java nie bekommen hat.
Deadalnix
4

Ich behandle erwartete Ausnahmen dort, wo ich sie erwarte. (Wie DB Lese- / Schreibfehler). Unerwartete Ausnahmen sprudele ich in die Luft. Irgendwo anders kann die Ausnahme erwartet werden und die Logik dafür haben.

SoylentGray
quelle
2

Ausnahmen sollten genau das sein .. Ausnahmen. Die beste Vorgehensweise bei der Verwendung von Ausnahmen besteht darin, sie zu verwenden, um die Situation abzudecken, in der etwas passiert, das nicht dem entspricht, was Sie erwarten würden. Das klassische Beispiel ist die FileNotFoundException, die ausgelöst wird, wenn eine Datei einfach nicht vorhanden ist. Wenn Sie die Existenz der Datei testen, verwenden Sie File.exists (), da Sie einfach mit einem 10-Fuß-Stick stoßen, um zu sehen, ob Sie etwas treffen.

Sie könnten technisch die gleichen Ergebnisse erzielen, indem Sie sie in einem Try-Catch umgeben und die Datei so verwenden, als ob sie vorhanden wäre. A) Ausnahmen sind jedoch im Allgemeinen ressourcenintensiv und B) Programmierer gehen davon aus, dass Sie gemeint haben, dass die Datei vorhanden ist, wenn sie vorhanden ist in einem Try-Catch, der zur allgemeinen Verwirrung eines Programms beiträgt.

Es gibt viele Situationen, in denen ich eine Methode schreibe, die einen Wert aus einer Datenbank abruft. Tausend Dinge könnten schief gehen, und da ich nur eine kleine Information benötige, ist es unpraktisch, den Anruf mit einer Try-Catch-Liste zu umgeben, die 5 verschiedene Ausnahmen enthält. Also werde ich Ausnahmen in der Abrufmethode abfangen. Wenn etwas schief geht, ergreife ich die entsprechenden Maßnahmen, um die Datenbankverbindung oder so weiter in der finally-Klausel zu schließen und null zurückzugeben. Dies ist eine gute Vorgehensweise, nicht nur, weil es Ihren Code vereinfacht, sondern auch, weil "null" dieselbe Nachricht sendet, die Sie von einer Ausnahme hätten erhalten können. Dass etwas nicht wie geplant gelaufen ist. Verwalten Sie Ausnahmespezifikationen in der Abrufmethode, aber verwalten Sie, was zu tun ist, wenn die Dinge nicht funktionieren.

Beispielsweise:

Integer getUserCount() {
   Integer result = null;
   try {
      // Attempt to open database and retrieve data
   } catch (TimeoutException e) {
      logger.error("Got a watch?");
   } catch (MissingDatabaseException e) {
      logger.error("What are you smoking?");
   } catch (PermissionsToReadException e) {
      logger.error("Did you *really* think you were getting away with that?");
   } catch (PressedSendButtonToHardException e) {
      logger.error("Seriously.. just back away from the computer... slowly..");
   } catch (WTFException e) {
      logger.error("You're on your own with this one.. I don't even know what happened..");
   } finally {
      // Close connections and whatnot
   }
   return result;
}

void doStuff() {
   Integer result = getUserCount();
   if(result != null) {
       // Went as planned..
   }
}
Neil
quelle
6
Wenn Sie File.exists () verwenden und sich auf das Ergebnis verlassen, kann eine Race-Bedingung auftreten, wenn die Datei direkt zwischen File.exists () und File.open () gelöscht wird. Wenn dies einen sicherheitskritischen Fehler auslöst, kann ein Angreifer diesen Zustand absichtlich verursachen. Aus diesem Grund ist es manchmal besser, die Operation atomar zu halten, dh es zu versuchen und die Ausnahme abzufangen.
user281377
1
Außerdem müssen Dateien vorhanden sein, damit die Anwendung ausgeführt werden kann. Das wären außergewöhnliche Bedingungen. Wenn es eine Datei gibt, die Sie benötigen, damit die Anwendung funktioniert, gibt es keinen Grund, nicht daraus zu lesen und dann die Ausnahme für den Ausnahmefall zu behandeln. Ich glaube, das macht die Absicht klarer.
Thomas Owens
Dies ist eine schlechte Entscheidung, null zurückzugeben. Es wird irgendwann zu einer NullPointerException führen und es wird wirklich schwierig sein zu debuggen, was schief gelaufen ist. Weil irgendwann jemand die Nullprüfung vergessen wird.
Deadalnix
@deadalnix: Ich könnte argumentieren, dass man sonst genauso leicht vergessen könnte, mit einem Try-Catch zu umgeben. Unterschied ist eine Frage des Stils, nicht der Funktionalität.
Neil
@ammoQ: Ich bin anderer Meinung. Ich denke, Sie sollten File.exists () verwenden und unter den seltenen Umständen, dass es gelöscht wird, bevor Sie es verwenden, ist eine Ausnahme mehr als angemessen. Der Unterschied besteht darin, wo Sie Ihren Fang aufbewahren. Haben Sie einfach einen pauschalen Ausnahmefänger für unerwartete Fehler, um ihn zu protokollieren und zu melden.
Neil
-5

Ja, Sie behandeln Laufzeitausnahmen korrekt. Dies ist keine gute Vorgehensweise. Der Grund dafür ist, dass dies als kostspielig / speicherintensiv angesehen wird.

Prasonscala
quelle
5
Hallo Prassee, können Sie Ihre Antwort näher erläutern? Einzeiler, die nicht mit Fakten, Referenzen oder Erfahrungen belegt sind, sind nicht sehr hilfreich.