Der Grund, warum Ausnahmen eine leistungsstarke Debugging -Methode sind, ist, dass sie die folgenden drei Fragen beantworten:
1. Was ist schief gelaufen?
2. Wo hast du einen Fehler gemacht?
3. Warum ist etwas schief gelaufen?
Bei einer effektiven Verwendung von Ausnahmen, der Ausnahmeart beantwortet "Was" ausgelöst wird, wird die Ausnahmestapel -Trace -Antworten "Wo" geworfen.
Es gibt drei Prinzipien, die Ihnen helfen können, die Verwendung guter Ausnahmen beim Debuggen zu maximieren. Diese drei Prinzipien sind:
1. spezifisch und klar
2. Wirf es früh
3.. Verzögerungserfassung
Um diese drei Prinzipien der effektiven Ausnahmebehandlung zu erläutern, wird dieser Artikel erörtert, indem ein persönlicher Finanzmanager JCheckbook fabriziert wird, mit dem Bankkontoaktivitäten wie Einlagen und Abhebungen und Rechnungsausgabe aufgezeichnet und verfolgt werden.
Konkret und klar
Java definiert eine Hierarchie einer Ausnahmeklasse, die mit Throwable, Fehlern und Ausnahme beginnt, und die Ausnahme erweitert RunTimeException. Wie in Abbildung 1 gezeigt.
Diese vier Klassen sind verallgemeinert und liefern nicht viele Fehlerinformationen. Obwohl die Instanziation dieser Klassen syntaktisch legal ist (wie: New Throwable ()), behandelt es am besten, sie als virtuelle Basisklassen zu behandeln und ihre spezialisierteren Unterklassen zu verwenden. Java hat eine große Anzahl von Ausnahmeunterklassen bereitgestellt. Wenn Sie genauer sein möchten, können Sie auch Ihre eigene Ausnahmeklasse definieren.
Zum Beispiel: Das Java.io -Paket definiert die Unterklasse der Ausnahmeklasse IOException, die spezialisierter und Unterklasse der IOException ist, wie z. Jedes beschreibt eine bestimmte Klasse von E/A -Fehlern: Dateiverlust, Ausnahmedateiend und fehler -serialisierte Objektströme. Je spezifischer die Ausnahme, desto in der Lage sein wird, die Frage "Was schief gelaufen ist" zu beantworten.
Es ist auch wichtig zu versuchen, beim Fangen von Ausnahmen so klar wie möglich zu sein. Zum Beispiel: JCheckbook kann FilenotFoundException verarbeiten, indem der Dateinamen des Benutzers erneut geeignet ist. Für die EOFException kann es weiterhin basierend auf den Informationen ausgeführt werden, die vor der Ausnahme gelesen wurden. Wenn eine ObjectStreamException geworfen wird, sollte das Programm den Benutzer auffordern, dass die Datei beschädigt ist und eine Sicherungsdatei oder eine andere Datei verwendet werden sollte.
Java erleichtert es einfach, explizit Ausnahmen zu fangen, da wir mehrere Fangblöcke für denselben Try -Block definieren können, damit jede Ausnahme getrennt angemessen behandelt werden kann.
Datei prefsFile = neue Datei (PrefsFileName); Versuchen Sie {ReadPreferences (Prefsfile);} catch (FilenotFoundException e) {// den Benutzer alarmieren, dass die angegebene Datei // nicht existiert} catch (eOfException e) {// alarmieren Sie den Benutzer, dass das Ende der Datei // die Datei erreicht wurde. Der Benutzer, den ein anderer I/O // -Fehler aufgetreten ist}JCheckbook bietet Benutzern explizite Informationen über die Erfassung von Ausnahmen mithilfe mehrerer Fangblöcke. Zum Beispiel: Wenn FilenotFoundException gefangen wird, kann der Benutzer aufgefordert werden, eine andere Datei anzugeben. In einigen Fällen kann der zusätzliche Codierungsaufwand durch mehrere Fangblöcke eine nicht wesentliche Belastung darstellen. In diesem Beispiel hilft der zusätzliche Code dem Programm jedoch eine benutzerfreundlichere Antwort.
Zusätzlich zu den Ausnahmen, die von den ersten drei Catch -Blöcken behandelt werden, bietet der letzte Catch -Block dem Benutzer allgemeinere Fehlerinformationen, wenn die IOException geworfen wird. Auf diese Weise kann das Programm so weit wie möglich spezifische Informationen liefern, kann aber auch andere unerwartete Ausnahmen behandeln.
Manchmal fangen Entwickler normalisierte Ausnahmen auf und zeigen den Namen der Ausnahmeklassen oder den Druckstapelinformationen für "Spezifität" an. Tu das nicht! Benutzer haben nur Kopfschmerzen, wenn sie java.io.EOFException oder stapelinformationen sehen, anstatt Hilfe zu erhalten. Spezifische Ausnahmen sollten erfasst werden und der Benutzer sollte mit "menschlichen Wörtern" aufgefordert werden. Der Ausnahmestapel kann jedoch in Ihrer Protokolldatei gedruckt werden. Denken Sie daran, Ausnahmen und Stapelinformationen werden verwendet, um Entwicklern und nicht zu Benutzern zu helfen.
Schließlich sollte angemerkt werden, dass JCheckbook keine Ausnahmen in readPreferences() fängt, sondern die Ausnahmen von Fang und Handeln von der Benutzeroberflächenschicht überlasst, damit Benutzer mithilfe von Dialogfeldern oder anderen Methoden benachrichtigt werden können. Dies wird als "Verzögerungserfassung" bezeichnet, die unten diskutiert wird.
Früh werfen
Ausnahmestapelinformationen liefern die genaue Reihenfolge der Methodenaufrufkette, die die Ausnahme erfolgt, einschließlich des Klassennamens, des Methodennamens, des Code -Dateinamens und der sogar Zeilennummer jeder Methodenaufruf, um die Szene, in der die Ausnahme auftritt, genau zu finden.
java.lang.nullpointerexceptionat java.io.fileinputstream.open (native Methode) unter java.io.fileinputstream. jCheckbook.jcheckbook.startup (jCheckbook.java:116) bei jCheckbook.jcheckbook.
Das obige zeigt den Fall, in dem die Open () -Methode der FileInputStream -Klasse eine NullPointerexception auswirkt. Beachten Sie jedoch, dass FileInputStream.close() Teil der Standard -Java -Klassenbibliothek ist, und es ist wahrscheinlich, dass das Problem dieser Ausnahme darin besteht, dass unser Code selbst nicht die Java -API ist. Das Problem wird daher wahrscheinlich in einer der vorherigen Methoden auftreten und wird glücklicherweise auch in den Stapelinformationen gedruckt.
Leider ist NullPointerexception die am wenigsten informative (aber auch die häufigsten und krachen) Ausnahme in Java. Es wird nicht erwähnt, was uns am meisten interessiert: Wo ist null. Also mussten wir ein paar Schritte zurück machen und herausfinden, wo etwas schief ging.
Bei der Unterstützung der Verfolgungsstapelinformationen und der Überprüfung des Code können wir feststellen, dass die Ursache des Fehlers darin besteht, dass ein leerer Dateiname -Parameter in readPreferences() übergeben wurde. Da readPreferences() weiß, dass es leere Dateinamen nicht verarbeiten kann, überprüfen Sie die Bedingung sofort:
public void ReadPreferences (String Dateiname) löst illegalArgumentException aus {if (fileName == null) {werfen Sie neue illegalArgumentException ("Dateiname null"); } // if //...Perform andere Operationen ... InputStream in = new FileInputStream (Dateiname); //...Lesen Sie die Datei der Einstellungen ...} Durch frühzeitiges Abgeben einer Ausnahme (auch schnell als "Misserfolg" bezeichnet) ist die Ausnahme klar und genau. Die Stapelinformationen spiegeln sofort wider, was schief gelaufen ist (es wurden illegale Parameterwerte bereitgestellt), warum es schief gelaufen ist (der Dateiname kann nicht null sein) und wo es schief gelaufen ist (der erste Teil von readPreferences() ). Auf diese Weise können unsere Stapelinformationen wahrheitsgemäß bereitgestellt werden:
Java.lang.ILLEGALARGUMENTException: Dateiname ist nullat jCheckbook.jcheckbook.readpreferences (jCheckbook.java:207) bei JCheckbook.jcheckbook.startup (jCheckbook.java:116) at jCheckbook.jCheckbook. jCheckbook.jcheckbook.main (jCheckbook.java:318)
Darüber hinaus machen die darin enthaltenen Ausnahmesinformationen ("Dateiname is leer") die Ausnahme reicher, indem sie ausdrücklich die Frage beantworten, was leer ist, was uns im vorherigen Code nicht zur Verfügung steht.
Der Fehler wird erreicht, indem eine Ausnahme sofort ausgelöst wird, wenn ein Fehler erkannt wird, kann unnötiges Objektkonstruktion oder Ressourcenverbrauch wie Datei oder Netzwerkverbindung effektiv vermieden werden. In ähnlicher Weise können die Reinigungsvorgänge durch Öffnen dieser Ressourcen gespeichert werden.
Verzögerte Erfassung
Ein Fehler, den sowohl Anfänger als auch Masters machen können, besteht darin, das Programm zu fangen, bevor es die Ausnahme bewältigen kann. Der Java -Compiler erleichtert dieses Verhalten indirekt, indem er verlangt, dass die geprüfte Ausnahme gefangen oder geworfen werden muss. Die natürliche Möglichkeit besteht darin, den Code sofort in einen Try -Block zu wickeln und Fang, um Ausnahmen zu fangen, um den Fehler des Compilers zu vermeiden.
Die Frage ist, was soll ich tun, wenn ich die Ausnahme bekomme, nachdem ich erwischt wurde? Das Schlimmste ist, nichts zu tun. Ein leerer Fangblock entspricht der Ausnahme der gesamten Ausnahme in das Schwarze Loch, und alle Informationen, die erklären können, wann, warum Fehler falsch sind, für immer verloren gehen. Es ist ein wenig besser, Ausnahmen in das Protokoll zu schreiben, zumindest gibt es Datensätze zu überprüfen. Wir können jedoch nicht erwarten, dass Benutzer Protokolldateien und Ausnahmeinformationen lesen oder verstehen. Es ist auch nicht geeignet, dass readPreferences() ein Fehlermeldungsdialog anzeigen kann, da JCheckbook derzeit eine Desktop-Anwendung ist, aber wir planen, es auch in eine HTML-basierte Webanwendung zu verwandeln. In diesem Fall ist das Anzeigen eines Fehlerdialogs offensichtlich keine Option. Gleichzeitig werden die Konfigurationsinformationen unabhängig von der HTML- oder C/S -Version auf dem Server gelesen, und die Fehlermeldung muss im Webbrowser- oder Client -Programm angezeigt werden. readPreferences() sollte diese zukünftigen Bedürfnisse auch beim Entwerfen berücksichtigen. Eine ordnungsgemäße Trennung des Benutzeroberflächencode und der Programmlogik kann die Wiederverwendbarkeit unseres Codes verbessern.
Vor dem bedingten Umgang mit einer Ausnahme zu erwischen, führt sie häufig zu schwerwiegenderen Fehlern und anderen Ausnahmen. Wenn beispielsweise readPreferences() -Methode die FileNotFoundException sofort erfasst und aufzeichnet, die möglicherweise geworfen werden kann, wenn der DateiInputStream -Konstruktor aufgerufen wird, wird der Code wie folgt:
public void ReadPreferences (String -Dateiname) {// ... inputStream in = null; // Tu dies nicht !!! Versuchen Sie {in = new FileInputStream (Dateiname);} catch (FilenotFoundException e) {logger.log (e);} in.read (...); // ...}Der obige Code erfasst es ohne die Möglichkeit, sich von FilenotFoundException wiederherzustellen. Wenn die Datei nicht gefunden werden kann, kann die folgende Methode sie offensichtlich nicht lesen. Was passiert, wenn ReadPreferences () gebeten wird, eine Datei zu lesen, die nicht vorhanden ist? Natürlich wird FilenotFoundException aufgezeichnet, und wenn wir uns die Protokolldatei zu diesem Zeitpunkt ansehen würden, würden wir es wissen. Was passiert jedoch, wenn ein Programm versucht, Daten aus einer Datei zu lesen? Da die Datei nicht vorhanden ist, ist die Variable in leer und eine NullPointerexception wird geworfen.
Beim Debuggen eines Programms fordert Instinct uns auf, uns die Informationen am Ende des Protokolls anzusehen. Das wäre nullPointerexception, und was sehr nervig ist, ist, dass diese Ausnahme sehr unspezifisch ist. Die Fehlermeldung führt uns nicht nur irre, was schief gelaufen ist (der eigentliche Fehler ist FileNotFoundException anstelle von NullPointerexception), sondern auch die Quelle des Fehlers irreführt. Das eigentliche Problem liegt außerhalb der Anzahl der Zeilen an der NullPointerexception, die mehrere Methodenaufrufe und Klassenzerstörungen aufweisen kann. Unsere Aufmerksamkeit wurde aus dem wirklichen Fehler des kleinen Fisches gelenkt, bis wir zurück auf das Protokoll schauten, um die Quelle des Problems zu finden.
Da readPreferences() wirklich nicht diese Ausnahmen erfassen sollte, was sollte es sein? Es scheint ein bisschen kontraintuitiv zu sein, und die am besten geeignete Möglichkeit ist, nichts zu tun und keine Ausnahmen sofort zu fangen. Überlassen Sie die Verantwortung dem Anrufer von readPreferences() und lassen Sie ihn den geeigneten Weg für fehlende Konfigurationsdateien untersuchen. Es kann den Benutzer auffordern, andere Dateien anzugeben oder den Standardwert zu verwenden. Wenn es wirklich nicht funktioniert, warnt es den Benutzer und beenden das Programm.
Der Weg, die Verantwortung für die Ausnahmeverarbeitung vor der Call -Kette zu übertragen, besteht darin, die Ausnahme in der Throw -Klausel der Methode zu deklarieren. Wenn Sie mögliche Ausnahmen deklarieren, seien Sie vorsichtig, desto spezifischer desto besser. Dies wird verwendet, um die Art der Ausnahme zu identifizieren, die das Programm, das Ihre Methode aufruft, kennen und bereit sein muss, um sie zu verarbeiten. Beispielsweise könnte die "Delay Capture" -Version von readPreferences() so aussehen:
public void ReadPreferences (String Dateiname) löst illegalArgumentException, FilenotFoundException, ioException {if (fileName == null) {Wurf neu illegalArgumentException ("Dateiname ist null"); } // if // ... inputStream in = new FileInputStream (Dateiname); // ...}Technisch gesehen ist die einzige Ausnahme, die wir deklarieren müssen, eine IOException, aber wir erklären ausdrücklich, dass die Methode eine FilenotFoundException werfen kann. IllegalArgumentException ist nicht erforderlich, um deklariert zu werden, da es sich um eine nicht überprüfende Ausnahme handelt (d. H. Eine Unterklasse von RunTimeException). Es wird jedoch erklärt, dass wir unseren Code dokumentieren (diese Ausnahmen sollten auch in den Javadocs der Methode gekennzeichnet sein).
Natürlich muss Ihr Programm irgendwann die Ausnahme einhalten, sonst endet es unerwartet. Der Trick hier besteht jedoch darin, Ausnahmen auf der richtigen Ebene zu fangen, damit Ihr Programm sich entweder sinnvoll von Ausnahmen erholen kann und weiterhin weitergeht, ohne tiefere Fehler zu verursachen. oder in der Lage sein, den Benutzern klare Informationen zu liefern, einschließlich der Anleitung, dass sie sich von Fehlern wiederherstellen. Wenn Ihre Methode nicht kompetent ist, bearbeiten Sie die Ausnahme nicht, lassen Sie sie zurück, um sie auf der richtigen Ebene zu fangen und zu behandeln.
Zusammenfassen
Erfahrene Entwickler wissen, dass die größte Schwierigkeit bei der Debuggierung von Programmen nicht darin besteht, Mängel zu beheben, sondern die Versteckplätze von Defekten aus einer riesigen Menge an Code herauszufinden. Solange Sie den drei Prinzipien dieses Artikels befolgen, können Ihre Ausnahmen Ihnen helfen, Mängel zu verfolgen und zu beseitigen, Ihr Programm robuster und benutzerfreundlicher zu machen. Das obige ist der gesamte Inhalt dieses Artikels, und ich hoffe, dass es Ihnen bei Ihrem Studium oder Ihrer Arbeit hilft.