Was ist ein Stack-Trace und wie kann ich damit meine Anwendungsfehler debuggen?

644

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.

Rob Hruska
quelle
25
Wenn eine Stacktrace-Zeile nicht den Dateinamen und eine Zeilennummer enthält, wurde die Klasse für diese Zeile nicht mit Debug-Informationen kompiliert.
Thorbjørn Ravn Andersen

Antworten:

589

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:

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)

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:

at com.example.myproject.Book.getTitle(Book.java:16)

Um dies zu debuggen, können wir die folgende Book.javaZeile öffnen und betrachten 16:

15   public String getTitle() {
16      System.out.println(title.toString());
17      return title;
18   }

Dies würde darauf hinweisen, dass sich (wahrscheinlich title) etwas nullim 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:

34   public void getBookIds(int id) {
35      try {
36         book.getId(id);    // this method it throws a NullPointerException on line 22
37      } catch (NullPointerException e) {
38         throw new IllegalStateException("A book has a null property", e)
39      }
40   }

Dadurch erhalten Sie möglicherweise eine Stapelverfolgung, die wie folgt aussieht:

Exception in thread "main" java.lang.IllegalStateException: A book has a null property
        at com.example.myproject.Author.getBookIds(Author.java:38)
        at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Caused by: java.lang.NullPointerException
        at com.example.myproject.Book.getId(Book.java:22)
        at com.example.myproject.Author.getBookIds(Author.java:36)
        ... 1 more

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:

Caused by: java.lang.NullPointerException <-- root cause
        at com.example.myproject.Book.getId(Book.java:22) <-- important line

Auch mit dieser Ausnahme würden wir auf Linie aussehen wollen 22von Book.javasehen , was die verursachen könnten NullPointerExceptionhier.

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):

javax.servlet.ServletException: Something bad happened
    at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:60)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.example.myproject.ExceptionHandlerFilter.doFilter(ExceptionHandlerFilter.java:28)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.example.myproject.OutputBufferFilter.doFilter(OutputBufferFilter.java:33)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:326)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
    at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:943)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at org.mortbay.jetty.bio.SocketConnector$Connection.run(SocketConnector.java:228)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: com.example.myproject.MyProjectServletException
    at com.example.myproject.MyServlet.doPost(MyServlet.java:169)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
    at com.example.myproject.OpenSessionInViewFilter.doFilter(OpenSessionInViewFilter.java:30)
    ... 27 more
Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.example.myproject.MyEntity]
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:64)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2329)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2822)
    at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)
    at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:321)
    at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
    at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:130)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:210)
    at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:56)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:195)
    at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:50)
    at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
    at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:705)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:693)
    at org.hibernate.impl.SessionImpl.save(SessionImpl.java:689)
    at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:344)
    at $Proxy19.save(Unknown Source)
    at com.example.myproject.MyEntityService.save(MyEntityService.java:59) <-- relevant call (see notes below)
    at com.example.myproject.MyServlet.doPost(MyServlet.java:164)
    ... 32 more
Caused by: java.sql.SQLException: Violation of unique constraint MY_ENTITY_UK_1: duplicate value(s) for column(s) MY_COLUMN in statement [...]
    at org.hsqldb.jdbc.Util.throwError(Unknown Source)
    at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source)
    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
    at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:57)
    ... 54 more

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.myprojectPaket enthalten wären . Im zweiten Beispiel (oben) möchten wir zunächst nach der Grundursache suchen:

Caused by: java.sql.SQLException

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:

at com.example.myproject.MyEntityService.save(MyEntityService.java:59)

Wie in den vorherigen Beispielen sollten wir uns das MyEntityService.javaonline ansehen 59, 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).

Rob Hruska
quelle
3
@ RobHruska - Sehr gut erklärt. +1. Kennen Sie Parser, die die Ausnahmeverfolgung als Zeichenfolge verwenden und nützliche Methoden zur Analyse der Stapelverfolgung bereitstellen? - wie getLastCausedBy () oder getCausedByForMyAppCode ("com.example.myproject")
Andy Dufresne
1
@AndyDufresne - Ich habe keine gefunden, aber andererseits habe ich auch nicht wirklich geschaut.
Rob Hruska
1
Verbesserungsvorschlag: Erklären Sie die erste Zeile eines Stack-Trace, mit der Sie 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.
Code-Apprentice
5
Außerdem hat Java 1.7 "Unterdrückt:" hinzugefügt. Hier werden die Stapelspuren für unterdrückte Ausnahmen aufgelistet, bevor für diese Ausnahme "Verursacht durch:" angezeigt wird. Es wird automatisch vom Try-with-Resource-Konstrukt verwendet: docs.oracle.com/javase/specs/jls/se8/html/… und enthält Ausnahmen, falls diese während des Schließens der Ressource (n) ausgelöst wurden.
Dhblah
Es gibt ein JEP openjdk.java.net/jeps/8220715 , das darauf abzielt, die Verständlichkeit insbesondere von NPEs weiter zu verbessern, indem Details wie "Feld 'nullInstanceField' kann nicht geschrieben werden, da 'this.nullInstanceField' null ist" bereitgestellt werden.
Mahatma_Fatal_Error
80

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:

Object a = null;
a.toString();                 //this line throws a NullPointerException

Object[] b = new Object[5];
System.out.println(b[10]);    //this line throws an IndexOutOfBoundsException,
                              //because b is only 5 elements long
int ia = 5;
int ib = 0;
ia = ia/ib;                   //this line throws an  ArithmeticException with the 
                              //message "/ by 0", because you are trying to
                              //divide by 0, which is not possible.

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 azu diesem Zeitpunkt niemals null ist. Sie können beispielsweise aeinen Scheck wie diesen initialisieren oder einschließen:

if (a!=null) {
    a.toString();
}

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 wiecatch (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.

try {
    Socket x = new Socket("1.1.1.1", 6789);
    x.getInputStream().read()
} catch (IOException e) {
    System.err.println("Connection could not be established, please try again later!")
}

Warum sollte ich nicht verwenden catch (Exception e)?

Lassen Sie uns anhand eines kleinen Beispiels zeigen, warum Sie nicht alle Ausnahmen abfangen sollten:

int mult(Integer a,Integer b) {
    try {
        int result = a/b
        return result;
    } catch (Exception e) {
        System.err.println("Error: Division by zero!");
        return 0;
    }
}

Was dieser Code versucht, ist, das ArithmeticExceptiondurch eine mögliche Division durch 0 verursachte zu fangen. Er fängt aber auch ein mögliches NullPointerException, das geworfen wird, wenn aoder bsind null. Dies bedeutet, dass Sie möglicherweise eine erhalten NullPointerException, 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

  1. Finden Sie heraus, was die Ursache für die Ausnahme ist, und beheben Sie sie, damit die Ausnahme überhaupt nicht ausgelöst wird.
  2. Wenn 1. nicht möglich ist, fangen Sie die spezifische Ausnahme ab und behandeln Sie sie.

    • Fügen Sie niemals nur einen Versuch / Fang hinzu und ignorieren Sie dann einfach die Ausnahme! Tu das nicht!
    • Niemals verwenden catch (Exception e), immer bestimmte Ausnahmen abfangen. Das erspart Ihnen viele Kopfschmerzen.
Dakkaron
quelle
1
schöne Erklärung, warum wir
Fehlermaskierung
2
Ich poste diese Antwort, damit die oberste Antwort (nach Aktivität sortiert) nicht einfach falsch ist. Ich habe keine Ahnung, von welcher Sie sprechen, da sich dies wahrscheinlich inzwischen geändert hat. Aber die akzeptierte Antwort ist definitiv interessanter;)
AxelH
1
Die, die ich meinte, wurde meines Wissens inzwischen gelöscht. Grundsätzlich hieß es: "Versuche einfach {} catch (Ausnahme e) {} und ignoriere alle Fehler". Die akzeptierte Antwort ist viel älter als meine Antwort, daher wollte ich eine etwas andere Sichtweise auf die Angelegenheit geben. Ich denke nicht, dass es jemandem hilft, nur die Antwort eines anderen zu kopieren oder zu behandeln, was andere Leute bereits gut behandelt haben.
Dakkaron
Es ist irreführend zu sagen "Keine Ausnahme fangen", das ist nur ein Anwendungsfall. Ihr Beispiel ist großartig, aber wie wäre es, wenn Sie sich oben in Ihrer Thread-Schleife befinden (Inside Run)? Sie sollten dort IMMER Ausnahmen (oder möglicherweise Throwable) abfangen und protokollieren, damit sie nicht unsichtbar verschwinden (Ausnahmen, die beim Ausführen ausgelöst werden, werden im Allgemeinen nicht korrekt protokolliert, es sei denn, Sie haben Ihren Thread / Logger dafür eingerichtet).
Bill K
1
Ich habe diesen Sonderfall nicht aufgenommen, da es nur um Multithreading geht. Beim Single-Threading beendet eine durchgesickerte Ausnahme das Programm und wird sichtbar protokolliert. Wenn jemand nicht weiß, wie er mit Ausnahmen richtig umgeht, weiß er normalerweise auch noch nicht, wie man Multithreading verwendet.
Dakkaron
21

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, firstNameder einen Wert enthält. Wir würden dies folgendermaßen tun:if(firstName == null || firstName.equals("")) return;

Das Obige verhindert, dass wir firstNameeinen 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.

Woot4Moo
quelle
Einverstanden. Dieser Ansatz könnte verwendet werden, um herauszufinden, welche Referenz in einer Aussage beispielsweise ist, nullwenn a NullPointerExceptionuntersucht wird.
Rob Hruska
16
Wenn Sie im Umgang mit String die Methode equals verwenden möchten, ist es meiner Meinung nach besser, die Konstante auf der linken Seite des Vergleichs wie folgt zu verwenden: Anstelle von: if (firstName == null || firstName.equals ("" )) Rückkehr; Ich benutze immer: if ((""). Equals (firstName)) Dies verhindert die Nullpointer-Ausnahme
Torres
15

Es gibt eine weitere Funktion von Stacktrace Throwable Familie angeboten - die Möglichkeit zu manipulieren Stack Trace - Informationen.

Standardverhalten:

package test.stack.trace;

public class SomeClass {

    public void methodA() {
        methodB();
    }

    public void methodB() {
        methodC();
    }

    public void methodC() {
        throw new RuntimeException();
    }

    public static void main(String[] args) {
        new SomeClass().methodA();
    }
}

Stapelspur:

Exception in thread "main" java.lang.RuntimeException
    at test.stack.trace.SomeClass.methodC(SomeClass.java:18)
    at test.stack.trace.SomeClass.methodB(SomeClass.java:13)
    at test.stack.trace.SomeClass.methodA(SomeClass.java:9)
    at test.stack.trace.SomeClass.main(SomeClass.java:27)

Manipulierte Stapelverfolgung:

package test.stack.trace;

public class SomeClass {

    ...

    public void methodC() {
        RuntimeException e = new RuntimeException();
        e.setStackTrace(new StackTraceElement[]{
                new StackTraceElement("OtherClass", "methodX", "String.java", 99),
                new StackTraceElement("OtherClass", "methodY", "String.java", 55)
        });
        throw e;
    }

    public static void main(String[] args) {
        new SomeClass().methodA();
    }
}

Stapelspur:

Exception in thread "main" java.lang.RuntimeException
    at OtherClass.methodX(String.java:99)
    at OtherClass.methodY(String.java:55)
przemek hertel
quelle
2
Ich weiß nicht, wie ich das finde ... Aufgrund der Art des Threads würde ich neuen Entwicklern raten, keinen eigenen Stack-Trace zu definieren.
PeonProgrammer
15

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. Geben Sie hier die Bildbeschreibung ein

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,

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)

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. Geben Sie hier die Bildbeschreibung ein

Kevin Li
quelle
8

Um die anderen Beispiele zu ergänzen, gibt es innere (verschachtelte) Klassen , die mit dem $Zeichen angezeigt werden. Zum Beispiel:

public class Test {

    private static void privateMethod() {
        throw new RuntimeException();
    }

    public static void main(String[] args) throws Exception {
        Runnable runnable = new Runnable() {
            @Override public void run() {
                privateMethod();
            }
        };
        runnable.run();
    }
}

Wird zu dieser Stapelverfolgung führen:

Exception in thread "main" java.lang.RuntimeException
        at Test.privateMethod(Test.java:4)
        at Test.access$000(Test.java:1)
        at Test$1.run(Test.java:10)
        at Test.main(Test.java:13)
Eugene S.
quelle
5

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).

Konsolentaste

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):

Diagramm 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.

rghome
quelle