Ich habe einen Code eines Kollegen gelesen und festgestellt, dass er häufig verschiedene Ausnahmen abfängt und stattdessen immer eine 'RuntimeException' auslöst. Ich fand das immer sehr schlecht. Liege ich falsch?
java
exceptions
exception-handling
RoflcoptrException
quelle
quelle
Function
,Predicate
usw.) haben werfen Klauseln nicht parametrisiert. Dies bedeutet , dass Sie brauchen zu fangen, wickeln, und rethrow alle geprüften Ausnahmen in der inneren Schleife von jedem Stream () Methoden. Das an und für sich gibt mir den Ausschlag, ob geprüfte Ausnahmen eine schlechte Idee sind.Antworten:
Ich kenne nicht genug Kontext, um zu wissen, ob Ihr Kollege etwas falsch macht oder nicht, deshalb werde ich im Allgemeinen darüber streiten.
Ich denke nicht, dass es immer eine falsche Praxis ist, geprüfte Ausnahmen in eine Art Laufzeitausnahme umzuwandeln . Überprüfte Ausnahmen werden häufig von Entwicklern missbraucht und missbraucht .
Es ist sehr einfach, geprüfte Ausnahmen zu verwenden, wenn sie nicht verwendet werden sollen (nicht behebbare Bedingungen oder sogar Kontrollfluss). Insbesondere wenn eine aktivierte Ausnahme für Bedingungen verwendet wird, unter denen der Aufrufer keine Wiederherstellung durchführen kann, ist es meines Erachtens gerechtfertigt, diese Ausnahme in eine Laufzeitausnahme mit einer hilfreichen Nachricht / einem hilfreichen Status umzuwandeln. Leider neigen sie in vielen Fällen dazu, einen leeren Fangblock zu haben, was eines der schlimmsten Dinge ist, die Sie tun können. Das Debuggen eines solchen Problems ist eines der größten Probleme, denen ein Entwickler begegnen kann.
Wenn Sie also der Meinung sind, dass es sich um eine wiederherstellbare Bedingung handelt, sollte diese entsprechend behandelt und die Ausnahme nicht in eine Laufzeitausnahme umgewandelt werden. Wenn eine aktivierte Ausnahme für nicht behebbare Bedingungen verwendet wird, ist die Umwandlung in eine Laufzeitausnahme gerechtfertigt .
quelle
Es kann gut sein . Bitte lesen Sie:
http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html
Es hilft nicht, geprüfte Ausnahmen auszulösen und sich nicht davon erholen zu können.
Einige Leute denken sogar, dass aktivierte Ausnahmen überhaupt nicht verwendet werden sollten. Siehe http://www.ibm.com/developerworks/java/library/j-jtp05254/index.html
Auch vom selben Link:
quelle
Nein, du liegst nicht falsch. Seine Praxis ist extrem fehlgeleitet. Sie sollten eine Ausnahme auslösen, die das Problem erfasst, das sie verursacht hat. RunTimeException ist umfassend und übergreifend. Es sollte eine NullPointerException, eine ArgumentException usw. sein. Was auch immer genau beschreibt, was schief gelaufen ist. Dies bietet die Möglichkeit, Probleme, die Sie behandeln sollten, zu unterscheiden und das Programm im Vergleich zu Fehlern überleben zu lassen, bei denen es sich um ein Szenario handeln sollte, bei dem "Nicht bestanden" handelt. Was er tut, ist nur geringfügig besser als "On Error Resume Next", es sei denn, in den in der Frage angegebenen Informationen fehlt etwas.
quelle
Es hängt davon ab, ob.
Diese Praxis kann sogar weise sein . Es gibt viele Situationen (zum Beispiel bei der Webentwicklung), in denen Sie im Ausnahmefall nichts tun können (weil Sie zum Beispiel keine inkonsistente Datenbank aus Ihrem Code reparieren können :-), dies kann nur der Entwickler tun). In diesen Situationen ist es ratsam, die ausgelöste Ausnahme in eine Laufzeitausnahme zu verpacken und sie erneut zu werfen. Dann können Sie alle diese Ausnahmen in einer Ausnahmebehandlungsebene abfangen, den Fehler protokollieren und dem Benutzer einen netten lokalisierten Fehlercode + eine Meldung anzeigen.
Auf der anderen Seite , wenn die Ausnahme nicht Laufzeit ist (wird überprüft), der Entwickler der API gibt an , dass diese Ausnahme auflösbar ist und soll repariert werden. Wenn es möglich ist, sollten Sie es auf jeden Fall tun.
Die andere Lösung könnte darin bestehen, diese aktivierte Ausnahme erneut in die aufrufende Ebene zu werfen. Wenn Sie sie jedoch nicht lösen konnten, wo die Ausnahme aufgetreten ist, können Sie sie wahrscheinlich auch hier nicht lösen ...
quelle
exception handling layer
- zB in einer Webapp, einem Filter.Ich würde gerne Kommentare dazu erhalten, aber ich finde, dass es Zeiten gibt, in denen dies nicht unbedingt eine schlechte Praxis ist. (Oder schrecklich schlecht). Aber vielleicht irre ich mich.
Häufig löst eine von Ihnen verwendete API eine Ausnahme aus, die Sie sich nicht vorstellen können, tatsächlich in Ihrem speziellen Anwendungsfall ausgelöst zu werden. In diesem Fall ist es völlig in Ordnung, eine RuntimeException mit der festgestellten Ausnahme als Ursache auszulösen. Wenn diese Ausnahme ausgelöst wird, ist dies wahrscheinlich die Ursache für Programmierfehler und liegt nicht innerhalb der Grenzen für die korrekte Spezifikation.
Vorausgesetzt, die RuntimeException wird später nicht abgefangen und ignoriert, ist sie nicht annähernd ein OnErrorResumeNext.
OnErrorResumeNext tritt auf, wenn eine Ausnahme abgefangen und einfach ignoriert oder nur ausgedruckt wird. Dies ist in fast allen Fällen eine schrecklich schlechte Praxis.
quelle
TL; DR
Prämisse
Fazit
Wir können eine aktivierte Ausnahme als Laufzeitausnahme erneut auslösen, wenn der Propagierungs- oder Schnittstellencode davon ausgeht, dass die zugrunde liegende Implementierung vom externen Status abhängt, wenn dies eindeutig nicht der Fall ist.
In diesem Abschnitt wird erläutert, wann eine der Ausnahmen ausgelöst werden soll. Sie können zur nächsten horizontalen Leiste springen, wenn Sie nur eine ausführlichere Erklärung für die Schlussfolgerung lesen möchten.
Wann ist es angebracht, eine Laufzeitausnahme auszulösen? Sie lösen eine Laufzeitausnahme aus, wenn klar ist, dass der Code nicht korrekt ist und die Wiederherstellung durch Ändern des Codes angemessen ist.
Beispielsweise ist es angebracht, eine Laufzeitausnahme für Folgendes auszulösen:
Dadurch wird eine Laufzeitausnahme für die Division durch Null ausgelöst. Dies ist angemessen, da der Code fehlerhaft ist.
Oder zum Beispiel, hier ist ein Teil von
HashMap
's Konstruktor:Um die anfängliche Kapazität oder den anfänglichen Auslastungsfaktor zu beheben, müssen Sie den Code bearbeiten, um sicherzustellen, dass die richtigen Werte übergeben werden. Dies hängt nicht davon ab, ob ein weit entfernter Server in Betrieb ist. eine Datei oder ein anderes Programm. Der Konstruktor, der mit ungültigen Argumenten aufgerufen wird, hängt von der Richtigkeit des aufrufenden Codes ab, sei es eine falsche Berechnung, die zu ungültigen Parametern oder einem unangemessenen Ablauf führte, bei dem ein Fehler übersehen wurde.
Wann ist es angebracht, eine aktivierte Ausnahme auszulösen? Sie werfen eine geprüfte Ausnahme , wenn das Problem ist ohne Änderung des Codes erstattungsfähig. Anders ausgedrückt, Sie lösen eine aktivierte Ausnahme aus, wenn der Fehler mit dem Status zusammenhängt, während der Code korrekt ist.
Jetzt kann das Wort "Wiederherstellen" hier schwierig sein. Dies kann bedeuten, dass Sie einen anderen Weg finden, um das Ziel zu erreichen: Wenn der Server beispielsweise nicht antwortet, sollten Sie den nächsten Server versuchen. Wenn diese Art der Wiederherstellung für Ihren Fall möglich ist, ist das großartig, aber das ist nicht das einzige, was Wiederherstellung bedeutet - Wiederherstellung könnte einfach darin bestehen, dem Benutzer einen Fehlerdialog anzuzeigen, der erklärt, was passiert ist, oder wenn es sich um eine Serveranwendung handelt, könnte dies der Fall sein Senden Sie eine E-Mail an den Administrator, oder protokollieren Sie den Fehler lediglich angemessen und präzise.
Nehmen wir das Beispiel, das in der Antwort von mrmuggles erwähnt wurde:
Dies ist nicht der richtige Weg, um die aktivierte Ausnahme zu behandeln. Die bloße Unfähigkeit, die Ausnahme im Geltungsbereich dieser Methode zu behandeln, bedeutet nicht, dass die App abstürzen sollte. Stattdessen ist es angebracht, es in einem höheren Bereich wie folgt zu verbreiten:
Was die Möglichkeit der Wiederherstellung durch den Anrufer ermöglicht:
Überprüfte Ausnahmen sind ein statisches Analysetool. Sie machen einem Programmierer klar, was bei einem bestimmten Aufruf schief gehen kann, ohne dass er die Implementierung erlernen oder einen Test- und Fehlerprozess durchlaufen muss. Auf diese Weise kann auf einfache Weise sichergestellt werden, dass keine Teile des Fehlerflusses ignoriert werden. Das erneute Auslösen einer aktivierten Ausnahme als Laufzeitausnahme wirkt sich auf diese arbeitssparende statische Analysefunktion aus.
Es ist auch erwähnenswert, dass die aufrufende Schicht einen besseren Kontext für das größere Schema der Dinge aufweist, wie oben gezeigt wurde. Es könnte viele Ursachen dafür geben,
dataAccessCode
dass angerufen werden würde, der konkrete Grund für den Anruf ist nur für den Anrufer sichtbar - somit ist es in der Lage, eine bessere Entscheidung bei der korrekten Wiederherstellung nach einem Ausfall zu treffen.Nachdem wir diese Unterscheidung getroffen haben, können wir ableiten, wann es in Ordnung ist, eine aktivierte Ausnahme erneut als Laufzeitausnahme zu werfen.
Wann ist es in Anbetracht des oben Gesagten angebracht, eine aktivierte Ausnahme erneut als RuntimeException auszugeben? Wenn der von Ihnen verwendete Code vom externen Status abhängig ist, können Sie jedoch eindeutig behaupten, dass er nicht vom externen Status abhängt.
Folgendes berücksichtigen:
In diesem Beispiel wird der Code weitergegeben,
IOException
da die API vonReader
für den Zugriff auf den externen Status ausgelegt ist. Wir wissen jedoch, dass dieStringReader
Implementierung nicht auf den externen Status zugreift. In diesem Bereich, in dem wir mit Sicherheit behaupten können, dass die an dem Aufruf beteiligten Teile nicht auf E / A oder einen anderen externen Zustand zugreifen, können wir die Ausnahme sicher als Laufzeitausnahme zurückwerfen, ohne Kollegen zu überraschen, die sich unserer Implementierung nicht bewusst sind (und dies möglicherweise tun) unter der Annahme, dass der IO-Zugangscode einenIOException
) auslöst .Der Grund für die strikte Überprüfung von externen zustandsabhängigen Ausnahmen ist, dass sie nicht deterministisch sind (im Gegensatz zu logikabhängigen Ausnahmen, die vorhersehbar jedes Mal für eine Version des Codes reproduziert werden). Wenn Sie beispielsweise versuchen, durch 0 zu dividieren, wird immer eine Ausnahme erzeugt. Wenn Sie nicht durch 0 dividieren, wird niemals eine Ausnahme erzeugt, und Sie müssen diesen Ausnahmefall nicht behandeln, da dies niemals passieren wird. Wenn Sie jedoch einmal auf eine Datei zugreifen, bedeutet dies nicht, dass Sie das nächste Mal erfolgreich sind - der Benutzer hat möglicherweise die Berechtigungen geändert, ein anderer Prozess hat sie möglicherweise gelöscht oder geändert. Sie müssen also immer mit diesem Ausnahmefall fertig werden, oder Sie haben wahrscheinlich einen Fehler.
quelle
Für eigenständige Anwendungen. Wenn Sie wissen, dass Ihre Anwendung die Ausnahme nicht verarbeiten kann, können Sie anstelle der aktivierten RuntimeException Error auslösen, die Anwendung abstürzen lassen, auf Fehlerberichte hoffen und die Anwendung reparieren. (Siehe die Antwort von mrmuggles für eine eingehendere Diskussion der Vor- und Nachteile von aktiviert und deaktiviert .)
quelle
Dies ist in vielen Frameworks üblich. ZB
Hibernate
macht genau das. Die Idee ist, dass die APIs für den Client nicht aufdringlich sein sollten undException
aufdringlich sind, da Sie explizit Code schreiben müssen, um sie an der Stelle zu verarbeiten, an der Sie die API aufrufen. Aber dieser Ort ist möglicherweise nicht der richtige Ort, um die Ausnahme überhaupt zu behandeln.Um ehrlich zu sein, ist dies ein "heißes" Thema und viele streiten sich, so dass ich keine Seite nehmen werde, aber ich werde sagen, dass das, was Ihr Freund tut / vorschlägt, nicht ungewöhnlich oder ungewöhnlich ist.
quelle
Die ganze "geprüfte Ausnahme" ist eine schlechte Idee.
Strukturierte Programmierung ermöglicht nur die Weitergabe von Informationen zwischen Funktionen (oder, in Java-Sprache, Methoden), wenn diese "in der Nähe" sind. Genauer gesagt, Informationen können sich nur auf zwei Arten über Funktionen hinweg bewegen:
Von einem Anrufer zu einem Angerufenen über die Weitergabe von Argumenten.
Vom Angerufenen zum Anrufer als Rückgabewert.
Das ist von Grund auf gut. Auf diese Weise können Sie lokal über Ihren Code nachdenken: Wenn Sie einen Teil Ihres Programms verstehen oder ändern müssen, müssen Sie sich nur diesen Teil und andere "nahe" liegende Teile ansehen.
Unter bestimmten Umständen ist es jedoch erforderlich, Informationen an eine "entfernte" Funktion zu senden, ohne dass es jemand in der Mitte "weiß". Genau hier müssen Ausnahmen verwendet werden. Eine Ausnahme ist eine geheime Nachricht, die von einem Auslöser (unabhängig davon, welcher Teil Ihres Codes eine
throw
Anweisung enthält) an einen Handler gesendet wird (unabhängig davon, welcher Teil Ihres Codes einencatch
Block enthält, der mit der Ausnahme kompatibel ist, diethrow
n war).Überprüfte Ausnahmen zerstören die Geheimhaltung des Mechanismus und damit den eigentlichen Grund für seine Existenz. Wenn eine Funktion es sich leisten kann, ihren Aufrufer eine Information "wissen" zu lassen, senden Sie diese Information einfach direkt als Teil des Rückgabewerts.
quelle
Dies kann von Fall zu Fall variieren. In bestimmten Szenarien ist es ratsam, das zu tun, was Ihr Freund tut, z. B. wenn Sie eine API für einige Clients bereitstellen und möchten, dass der Client die Implementierungsdetails am wenigsten kennt, von denen Sie wissen, dass bestimmte Implementierungsausnahmen spezifisch sind Implementierungsdetails und nicht für den Client verfügbar.
Indem Sie die aktivierten Ausnahmen aus dem Weg räumen, können Sie APIs bereitstellen, die es dem Client ermöglichen, saubereren Code zu schreiben, da der Client selbst möglicherweise die Ausnahmebedingungen vorab überprüft.
Beispielsweise nimmt Integer.parseInt (String) einen String und gibt dessen ganzzahliges Äquivalent zurück und löst NumberFormatException aus, falls der String nicht numerisch ist. Stellen Sie sich vor, eine Formularübermittlung mit einem Feld
age
wird mit dieser Methode konvertiert, der Client hätte jedoch bereits die Validierung sichergestellt, sodass es keinen Grund gibt, die Prüfung auf Ausnahmen zu erzwingen.quelle
Hier gibt es wirklich ein paar Fragen
Die allgemeine Faustregel lautet, dass Ausnahmen, von denen der Anrufer erwartet, dass sie abgefangen und behoben werden, überprüft werden sollten. Andere Ausnahmen (Ausnahmen, bei denen das einzige vernünftige Ergebnis darin besteht, den gesamten Vorgang abzubrechen, oder bei denen Sie der Ansicht sind, dass es sich nicht lohnt, sich Gedanken über den Umgang mit ihnen zu machen), sollten deaktiviert werden.
Manchmal unterscheidet sich Ihre Beurteilung, ob eine Ausnahme das Abfangen und Wiederherstellen verdient, von der der API, mit der Sie arbeiten. Manchmal spielt der Kontext eine Rolle. Eine Ausnahme, die in einer bestimmten Situation eine Behandlung wert ist, ist in einer anderen möglicherweise keine Behandlung wert. Manchmal wird Ihre Hand durch vorhandene Schnittstellen gezwungen. Es gibt also berechtigte Gründe, eine aktivierte Ausnahme in eine nicht aktivierte Ausnahme (oder in einen anderen Typ einer aktivierten Ausnahme) umzuwandeln.
Stellen Sie zunächst und vor allem sicher, dass Sie die Funktion zum Verketten von Ausnahmen verwenden. Auf diese Weise gehen die Informationen aus der ursprünglichen Ausnahme nicht verloren und können zum Debuggen verwendet werden.
Zweitens müssen Sie entscheiden, welcher Ausnahmetyp verwendet werden soll. Die Verwendung einer einfachen Laufzeitausnahme erschwert es dem Aufrufer zu bestimmen, was schief gelaufen ist, aber wenn der Aufrufer versucht, zu bestimmen, was schief gelaufen ist, kann dies ein Hinweis darauf sein, dass Sie die Ausnahme nicht geändert haben sollten, um sie zu deaktivieren.
quelle
Bei einer Booleschen Frage ist es nach zwei kontroversen Antworten schwer, anders zu antworten, aber ich möchte Ihnen eine Perspektive geben, die selbst an wenigen Stellen erwähnt wurde, aber nicht genug betont wurde für die Bedeutung, die sie hat.
Mit den Jahren stellte ich fest, dass immer jemand über ein triviales Problem verwirrt ist, dem es an Verständnis für einige der Grundlagen mangelt.
Schichtung. Eine Software-Anwendung (sollte es zumindest sein), die aus mehreren übereinander liegenden Schichten besteht. Eine wichtige Voraussetzung für eine gute Schichtung ist, dass die unteren Schichten Funktionen für potenziell mehrere Komponenten aus der oberen Schicht bereitstellen.
Angenommen, Ihre App verfügt über die folgenden Ebenen von Grund auf: NET, TCP, HTTP, REST, DATENMODELL, BUSINESS.
Wenn Ihre Business-Schicht einen Rest-Anruf ausführen möchte ... warten Sie eine Sekunde. Warum habe ich das gesagt? Warum habe ich keine HTTP-Anfrage oder TCP-Transaktion gesendet oder Netzwerkpakete gesendet? Weil diese für meine Geschäftsschicht irrelevant sind. Ich werde nicht mit ihnen umgehen, ich werde nicht in die Details von ihnen schauen. Ich bin vollkommen in Ordnung, wenn sie tief in den Ausnahmen liegen, die ich als Ursache nehme, und ich möchte nicht wissen, dass sie überhaupt existieren.
Außerdem ist es schlecht, wenn ich Details kenne, denn wenn ich morgen die unterstrichenen Transportprotokolle ändern möchte, die sich auf Details beziehen, die für das TCP-Protokoll spezifisch sind, hat meine REST-Abstraktion keine gute Arbeit geleistet, um sich selbst zu abstrahieren die konkrete Umsetzung.
Beim Übergang einer Ausnahme von Ebene zu Ebene ist es wichtig, jeden Aspekt zu überdenken und festzustellen, welchen Sinn dies für die von der aktuellen Ebene bereitgestellte Abstraktion hat. Es kann sein, dass die Ausnahme durch eine andere ersetzt wird und mehrere Ausnahmen kombiniert werden. Sie können auch von aktiviert auf deaktiviert oder umgekehrt umgestellt werden.
Natürlich ist es eine andere Geschichte, wenn die von Ihnen genannten Orte sinnvoll sind, aber im Allgemeinen - ja, es könnte eine gute Sache sein, dies zu tun.
quelle
Meiner Meinung nach,
Auf der Framework-Ebene sollten Laufzeitausnahmen abgefangen werden, um mehr Block-of-Try-Catch für den Aufrufer an derselben Stelle zu reduzieren.
In der Anwendungsebene erfassen wir selten Laufzeitausnahmen, und ich denke, diese Praxis war schlecht.
quelle