Wenn ich meine Anwendung ausführe, wird manchmal ein Fehler angezeigt, der wie folgt aussieht:
Exception in thread "main" java.lang.NullPointerException
at com.example.myproject.Book.getTitle(Book.java:16)
at com.example.myproject.Author.getBookTitles(Author.java:25)
at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Die Leute haben dies als "Stack-Trace" bezeichnet. Was ist eine Stapelverfolgung? Was kann es mir über den Fehler sagen, der in meinem Programm auftritt?
Zu dieser Frage - ziemlich oft sehe ich eine Frage, bei der ein unerfahrener Programmierer "einen Fehler bekommt", und sie fügen einfach ihren Stack-Trace und einen zufälligen Codeblock ein, ohne zu verstehen, was der Stack-Trace ist oder wie sie ihn verwenden können. Diese Frage ist als Referenz für unerfahrene Programmierer gedacht, die möglicherweise Hilfe zum Verständnis des Werts einer Stapelverfolgung benötigen.
java
debugging
stack-trace
Rob Hruska
quelle
quelle
Antworten:
In einfachen Worten ist ein Stack-Trace eine Liste der Methodenaufrufe, bei denen sich die Anwendung in der Mitte befand, als eine Ausnahme ausgelöst wurde.
Einfaches Beispiel
Anhand des Beispiels in der Frage können wir genau bestimmen, wo die Ausnahme in der Anwendung ausgelöst wurde. Werfen wir einen Blick auf die Stapelverfolgung:
Dies ist eine sehr einfache Stapelverfolgung. Wenn wir am Anfang der Liste von "at ..." beginnen, können wir feststellen, wo unser Fehler aufgetreten ist. Was wir suchen, ist der oberste Methodenaufruf, der Teil unserer Anwendung ist. In diesem Fall ist es:
Um dies zu debuggen, können wir die folgende
Book.java
Zeile öffnen und betrachten16
:Dies würde darauf hinweisen, dass sich (wahrscheinlich
title
) etwasnull
im obigen Code befindet.Beispiel mit einer Kette von Ausnahmen
Manchmal fangen Anwendungen eine Ausnahme ab und werfen sie erneut als Ursache für eine andere Ausnahme. Dies sieht normalerweise so aus:
Dadurch erhalten Sie möglicherweise eine Stapelverfolgung, die wie folgt aussieht:
Was an diesem anders ist, ist das "Verursacht von". Manchmal haben Ausnahmen mehrere Abschnitte "Verursacht durch". Für diese möchten Sie normalerweise die "Grundursache" finden, die einer der niedrigsten Abschnitte "Verursacht durch" in der Stapelverfolgung ist. In unserem Fall ist es:
Auch mit dieser Ausnahme würden wir auf Linie aussehen wollen
22
vonBook.java
sehen , was die verursachen könntenNullPointerException
hier.Entmutigenderes Beispiel mit Bibliothekscode
Normalerweise sind Stapelspuren viel komplexer als die beiden obigen Beispiele. Hier ist ein Beispiel (es ist lang, zeigt aber mehrere Ebenen verketteter Ausnahmen):
In diesem Beispiel gibt es noch viel mehr. Was uns am meisten beschäftigt, ist die Suche nach Methoden aus unserem Code , die alles im
com.example.myproject
Paket enthalten wären . Im zweiten Beispiel (oben) möchten wir zunächst nach der Grundursache suchen:Alle Methodenaufrufe darunter sind jedoch Bibliothekscode. Wir gehen also zu "Caused by" darüber und suchen nach dem ersten Methodenaufruf, der von unserem Code stammt:
Wie in den vorherigen Beispielen sollten wir uns das
MyEntityService.java
online ansehen59
, da dort dieser Fehler entstanden ist (dies ist ein bisschen offensichtlich, was schief gelaufen ist, da die SQLException den Fehler angibt, aber das Debugging-Verfahren ist das, wonach wir suchen).quelle
Exception in thread "main"
in Ihrem ersten Beispiel beginnen. Ich denke, es wäre besonders hilfreich zu erklären, dass diese Zeile häufig von einer Meldung begleitet wird, z. B. dem Wert einer Variablen, die bei der Diagnose des Problems hilfreich sein kann. Ich habe versucht, selbst eine Bearbeitung vorzunehmen, aber ich habe Mühe, diese Ideen in die vorhandene Struktur Ihrer Antwort zu integrieren.Ich poste diese Antwort, damit die oberste Antwort (nach Aktivität sortiert) nicht einfach falsch ist.
Was ist ein Stacktrace?
Ein Stacktrace ist ein sehr hilfreiches Debugging-Tool. Es zeigt den Aufrufstapel (dh den Stapel von Funktionen, die bis zu diesem Zeitpunkt aufgerufen wurden) zum Zeitpunkt des Auslösens einer nicht erfassten Ausnahme (oder zum Zeitpunkt der manuellen Generierung des Stacktraces). Dies ist sehr nützlich, da es Ihnen nicht nur zeigt, wo der Fehler aufgetreten ist, sondern auch, wie das Programm an dieser Stelle des Codes gelandet ist. Dies führt zur nächsten Frage:
Was ist eine Ausnahme?
Eine Ausnahme ist das, was die Laufzeitumgebung verwendet, um Ihnen mitzuteilen, dass ein Fehler aufgetreten ist. Beliebte Beispiele sind NullPointerException, IndexOutOfBoundsException oder ArithmeticException. Jedes dieser Probleme tritt auf, wenn Sie versuchen, etwas zu tun, das nicht möglich ist. Beispielsweise wird eine NullPointerException ausgelöst, wenn Sie versuchen, ein Null-Objekt dereferenzieren:
Wie soll ich mit Stacktraces / Ausnahmen umgehen?
Finden Sie zunächst heraus, was die Ausnahme verursacht. Versuchen Sie, den Namen der Ausnahme zu googeln, um herauszufinden, was die Ursache für diese Ausnahme ist. Meistens wird es durch falschen Code verursacht. In den obigen Beispielen werden alle Ausnahmen durch falschen Code verursacht. Für das NullPointerException-Beispiel können Sie also sicherstellen, dass dies
a
zu diesem Zeitpunkt niemals null ist. Sie können beispielsweisea
einen Scheck wie diesen initialisieren oder einschließen:Auf diese Weise wird die fehlerhafte Zeile nicht ausgeführt, wenn
a==null
. Gleiches gilt für die anderen Beispiele.Manchmal können Sie nicht sicherstellen, dass Sie keine Ausnahme erhalten. Wenn Sie beispielsweise eine Netzwerkverbindung in Ihrem Programm verwenden, können Sie den Computer nicht daran hindern, die Internetverbindung zu verlieren (z. B. können Sie den Benutzer nicht daran hindern, die Netzwerkverbindung des Computers zu trennen). In diesem Fall wird die Netzwerkbibliothek wahrscheinlich eine Ausnahme auslösen. Jetzt sollten Sie die Ausnahme abfangen und behandeln . Dies bedeutet, dass Sie im Beispiel mit der Netzwerkverbindung versuchen sollten, die Verbindung erneut zu öffnen oder den Benutzer oder ähnliches zu benachrichtigen. Wenn Sie catch verwenden, fangen Sie immer nur die Ausnahme ab, die Sie fangen möchten. Verwenden Sie keine allgemeinen catch-Anweisungen wie
catch (Exception e)
das würde alle Ausnahmen fangen. Dies ist sehr wichtig, da Sie sonst möglicherweise versehentlich die falsche Ausnahme abfangen und falsch reagieren.Warum sollte ich nicht verwenden
catch (Exception e)
?Lassen Sie uns anhand eines kleinen Beispiels zeigen, warum Sie nicht alle Ausnahmen abfangen sollten:
Was dieser Code versucht, ist, das
ArithmeticException
durch eine mögliche Division durch 0 verursachte zu fangen. Er fängt aber auch ein möglichesNullPointerException
, das geworfen wird, wenna
oderb
sindnull
. Dies bedeutet, dass Sie möglicherweise eine erhaltenNullPointerException
, diese jedoch als ArithmeticException behandeln und wahrscheinlich das Falsche tun. Im besten Fall vermissen Sie immer noch, dass es eine NullPointerException gab. Solche Dinge erschweren das Debuggen erheblich. Tun Sie das also nicht.TLDR
Wenn 1. nicht möglich ist, fangen Sie die spezifische Ausnahme ab und behandeln Sie sie.
catch (Exception e)
, immer bestimmte Ausnahmen abfangen. Das erspart Ihnen viele Kopfschmerzen.quelle
Um das zu ergänzen, was Rob erwähnt hat. Das Festlegen von Haltepunkten in Ihrer Anwendung ermöglicht die schrittweise Verarbeitung des Stapels. Auf diese Weise kann der Entwickler mithilfe des Debuggers feststellen, an welchem genauen Punkt die Methode etwas Unerwartetes ausführt.
Da Rob die
NullPointerException
(NPE) verwendet hat, um etwas Gemeinsames zu veranschaulichen, können wir helfen, dieses Problem auf folgende Weise zu beheben:Wenn wir eine Methode haben, die Parameter wie:
void (String firstName)
In unserem Code möchten wir auswerten,
firstName
der einen Wert enthält. Wir würden dies folgendermaßen tun:if(firstName == null || firstName.equals("")) return;
Das Obige verhindert, dass wir
firstName
einen unsicheren Parameter verwenden. Daher können wir durch Nullprüfungen vor der Verarbeitung sicherstellen, dass unser Code ordnungsgemäß ausgeführt wird. Um ein Beispiel zu erweitern, das ein Objekt mit Methoden verwendet, können wir hier nachsehen:if(dog == null || dog.firstName == null) return;
Das Obige ist die richtige Reihenfolge, um nach Nullen zu suchen. Wir beginnen mit dem Basisobjekt, in diesem Fall Hund, und gehen dann den Baum der Möglichkeiten entlang, um sicherzustellen, dass alles gültig ist, bevor wir es verarbeiten. Wenn die Reihenfolge umgekehrt würde, könnte möglicherweise eine NPE ausgelöst werden und unser Programm würde abstürzen.
quelle
null
wenn aNullPointerException
untersucht wird.Es gibt eine weitere Funktion von Stacktrace Throwable Familie angeboten - die Möglichkeit zu manipulieren Stack Trace - Informationen.
Standardverhalten:
Stapelspur:
Manipulierte Stapelverfolgung:
Stapelspur:
quelle
Den Namen verstehen : Eine Stapelverfolgung ist eine Liste von Ausnahmen (oder Sie können eine Liste von "Ursache durch" sagen), von der oberflächlichsten Ausnahme (z. B. Service-Layer-Ausnahme) bis zur tiefsten Ausnahme (z. B. Datenbankausnahme). Genau wie der Grund, warum wir es "Stapel" nennen, ist, dass der Stapel "First in Last out" (FILO) ist, die tiefste Ausnahme am Anfang aufgetreten ist, dann wurde eine Ausnahmekette mit einer Reihe von Konsequenzen generiert, die Oberflächenausnahme war die letzte eines ist rechtzeitig passiert, aber wir sehen es an erster Stelle.
Schlüssel 1 : Eine schwierige und wichtige Sache, die hier verstanden werden muss, ist: Die tiefste Ursache ist möglicherweise nicht die "Grundursache", denn wenn Sie einen "schlechten Code" schreiben, kann dies zu einer Ausnahme führen, die tiefer liegt als die Ebene. Beispielsweise kann eine fehlerhafte SQL-Abfrage dazu führen, dass die SQLServerException-Verbindung im unteren Bereich zurückgesetzt wird, anstatt dass ein Syndax-Fehler auftritt, der sich möglicherweise genau in der Mitte des Stapels befindet.
-> Finden Sie die Grundursache in der Mitte ist Ihre Aufgabe.
Schlüssel 2 : Eine weitere knifflige, aber wichtige Sache befindet sich in jedem "Cause by" -Block. Die erste Zeile war die tiefste Ebene und hat für diesen Block den ersten Platz belegt. Zum Beispiel,
Book.java:16 wurde von Auther.java:25 aufgerufen, was von Bootstrap.java:14 aufgerufen wurde. Book.java:16 war die Hauptursache. Fügen Sie hier ein Diagramm hinzu, das den Trace-Stapel in chronologischer Reihenfolge sortiert.
quelle
Um die anderen Beispiele zu ergänzen, gibt es innere (verschachtelte) Klassen , die mit dem
$
Zeichen angezeigt werden. Zum Beispiel:Wird zu dieser Stapelverfolgung führen:
quelle
Die anderen Beiträge beschreiben, was ein Stack-Trace ist, aber es kann immer noch schwierig sein, damit zu arbeiten.
Wenn Sie eine Stapelverfolgung erhalten und die Ursache der Ausnahme verfolgen möchten, ist die Verwendung der Java-Stapelverfolgungskonsole in Eclipse ein guter Ausgangspunkt für das Verständnis . Wenn Sie eine andere IDE verwenden, gibt es möglicherweise eine ähnliche Funktion, aber diese Antwort bezieht sich auf Eclipse.
Stellen Sie zunächst sicher, dass alle Java-Quellen in einem Eclipse-Projekt verfügbar sind.
Klicken Sie dann in der Java- Perspektive auf die Registerkarte Konsole (normalerweise unten). Wenn die Konsolenansicht nicht sichtbar ist, gehen Sie zur Menüoption Fenster -> Ansicht anzeigen und wählen Sie Konsole .
Klicken Sie dann im Konsolenfenster auf die folgende Schaltfläche (rechts).
Wählen Sie dann Java Stack Trace Console aus der Dropdown-Liste aus.
Fügen Sie Ihren Stack-Trace in die Konsole ein. Anschließend wird eine Liste mit Links zu Ihrem Quellcode und allen anderen verfügbaren Quellcodes angezeigt.
Folgendes sehen Sie möglicherweise (Bild aus der Eclipse-Dokumentation):
Der jüngste gemacht Methodenaufruf wird die seine Oberseite des Stapels, die die obere Zeile ist ( mit Ausnahme des Meldungstextes). Den Stapel runter zu gehen geht in der Zeit zurück. Die zweite Zeile ist die Methode, die die erste Zeile usw. aufruft.
Wenn Sie Open-Source-Software verwenden, müssen Sie möglicherweise die Quellen herunterladen und an Ihr Projekt anhängen, wenn Sie sie untersuchen möchten. Laden Sie die Quellgläser herunter. Öffnen Sie in Ihrem Projekt den Ordner " Referenzierte Bibliotheken ", um Ihr Glas für Ihr Open-Source-Modul (das mit den Klassendateien) zu finden. Klicken Sie dann mit der rechten Maustaste, wählen Sie Eigenschaften und hängen Sie das Quellglas an.
quelle