Ich möchte hier hinzufügen, dass die Behandlung von Ausnahmen in fast allen Java-Codes, die ich gesehen habe, einfach falsch ist. D.h. man bekommt sehr schwer zu debuggende Fehler für ignorierte Exceptions, oder, was genauso schlimm ist, man bekommt eine obskure Exception, die einem nichts sagt, weil man blind dem "catching(Exception) is bad" folgt und die Dinge sind einfach schlimmer.
Verstehen Sie zunächst, dass eine Ausnahme eine Möglichkeit ist, die Rückgabe von Fehlerinformationen über Codeschichten hinweg zu erleichtern. Fehler 1: Eine Schicht ist nicht nur ein Stackframe, eine Schicht ist Code, der eine genau definierte Verantwortung hat. Wenn Sie Schnittstellen und Impls einfach nur so kodiert haben, dann haben Sie Besseres zu tun.
Wenn die Ebenen gut gestaltet sind und bestimmte Zuständigkeiten haben, dann hat die Information des Fehlers eine andere Bedeutung, wenn sie auftaucht. <-das ist der Schlüssel zu dem, was zu tun ist, es gibt keine universelle Regel.
Das bedeutet also, dass Sie beim Auftreten einer Ausnahme 2 Möglichkeiten haben, aber Sie müssen wissen, wo in der Ebene Sie sich befinden:
A) Wenn Sie sich in der Mitte einer Schicht befinden und Sie nur eine interne, normalerweise private Hilfsfunktion sind und etwas schief geht: DONT WORRY, lassen Sie den Aufrufer die Ausnahme erhalten. Das ist völlig in Ordnung, denn Sie haben keinen geschäftlichen Kontext und 1) Sie ignorieren den Fehler nicht und 2) Der Aufrufer ist Teil Ihrer Schicht und hätte wissen müssen, dass so etwas passieren kann, aber Sie haben jetzt vielleicht nicht den Kontext, um es unten zu behandeln.
oder ...
B) Sie sind die obere Grenze der Schicht, die Fassade zu den Interna. Wenn dann eine Ausnahme auftritt, ist die Standardeinstellung CATCH ALL und verhindert, dass bestimmte Ausnahmen in die obere Schicht gelangen, was für den Aufrufer keinen Sinn macht, oder noch schlimmer, Sie könnten sich ändern und der Aufrufer hat eine Abhängigkeit zu einem Implementierungsdetail und beide brechen.
Die Stärke einer Anwendung ist der Entkopplungsgrad zwischen den Schichten. Hier wird in der Regel alles gestoppt und der Fehler mit einer generischen Ausnahme zurückgeworfen, die die Informationen in einen aussagekräftigeren Fehler für die obere Schicht übersetzt.
REGEL: Alle Eingangspunkte zu einer Schicht müssen mit CATCH ALL geschützt und alle Fehler übersetzt oder behandelt werden. Nun kommt diese "Behandlung" nur in 1% der Fälle vor, meistens muss (oder kann) man den Fehler nur in einer korrekten Abstraktion zurückgeben.
Nein, ich bin sicher, das ist sehr schwer zu verstehen. echtes Beispiel ->
Ich habe ein Paket, das einige Simulationen durchführt. Diese Simulationen sind in Text-Skripten. Es gibt ein Paket, das diese Skripte kompiliert und es gibt ein generisches utils-Paket, das nur Textdateien und natürlich die Basis-Java-RTL liest. Die UML-Abhängigkeit ist->
Simulator->Compiler->utilsTextLoader->Java-Datei
1) Wenn etwas im Utilities-Loader innerhalb eines Private kaputt geht und ich eine FileNotFound, Permissions oder was auch immer bekomme, dann lass es einfach durchgehen. Es gibt nichts anderes, was Sie tun können.
2) An der Grenze, in der Funktion utilsTextLoader, die zunächst aufgerufen wird, folgen Sie der obigen Regel und CATCH_ALL. Dem Compiler ist es egal, was passiert, er muss nur wissen, ob die Datei geladen wurde oder nicht. In der Catch-Funktion werfen Sie also eine neue Exception und übersetzen die FileNotFound oder was auch immer in "Could not read file XXXX".
3) Der Compiler weiß nun, dass die Quelle nicht geladen wurde. Das ist ALLES, was er wissen muss. Wenn ich also später utilsTestLoader ändere, um vom Netzwerk zu laden, wird sich der Compiler nicht ändern. Wenn Sie FileNotFound loslassen und später ändern, wird der Compiler umsonst beeinflusst.
4) Der Zyklus wiederholt sich: Die eigentliche Funktion, die die untere Schicht für die Datei aufgerufen hat, tut nichts, wenn sie die Ausnahme erhält. Sie lässt sie also nach oben gehen.
5) Wenn die Ausnahme die Schicht zwischen Simulator und Compiler erreicht, wird der Compiler wieder CATCHES_ALL, wobei er alle Details ausblendet und nur einen spezifischeren Fehler ausgibt: "Could not compile script XXX"
6) Zum Schluss wiederholen Sie den Zyklus ein weiteres Mal, die Simulatorfunktion, die den Compiler aufgerufen hat, lässt einfach los.
7) Die letzte Grenze liegt beim Nutzer. Der Benutzer ist ein LAYER und alles gilt. Die wichtigsten hat eine versuchen, dass catches_ALL und schließlich macht nur ein schönes Dialogfeld oder Seite und "wirft" einen übersetzten Fehler an den Benutzer.
So sieht der Benutzer.
Simulator: Fataler Fehler: Simulator konnte nicht gestartet werden
-Compiler: Das Skript FOO1 konnte nicht kompiliert werden.
-TextLoader: Konnte Datei foo1.scp nicht lesen
---trl: FileNotFound
Vergleichen mit:
a) Compiler: NullPointer Exception <-Häufiger Fall und eine verlorene Nacht beim Debuggen eines Dateinamen-Tippfehlers
b) Lader: Datei nicht gefunden <- Habe ich schon erwähnt, dass Loader hunderte von Skripten lädt?
oder
c) Es passiert nichts, weil alles ignoriert wurde!!!
Dies setzt natürlich voraus, dass Sie bei jedem Rückwurf nicht vergessen haben, die Ausnahmeursache zu setzen.
Nun meine 2cts. Diese einfachen Regeln haben mir schon oft das Leben gerettet...
-Ale
0 Stimmen
Könnten Sie das genaue Nutzungsszenario beschreiben?