Java 什么是堆栈跟踪,我如何使用它来调试我的应用程序错误?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3988788/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 08:00:24  来源:igfitidea点击:

What is a stack trace, and how can I use it to debug my application errors?

javadebuggingstack-trace

提问by Rob Hruska

Sometimes when I run my application it gives me an error that looks like:

有时,当我运行我的应用程序时,它会给我一个如下所示的错误:

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)

People have referred to this as a "stack trace". What is a stack trace?What can it tell me about the error that's happening in my program?

人们将此称为“堆栈跟踪”。什么是堆栈跟踪?关于我的程序中发生的错误,它可以告诉我什么?



About this question - quite often I see a question come through where a novice programmer is "getting an error", and they simply paste their stack trace and some random block of code without understanding what the stack trace is or how they can use it. This question is intended as a reference for novice programmers who might need help understanding the value of a stack trace.

关于这个问题 - 我经常看到一个问题是新手程序员“遇到错误”,他们只是粘贴他们的堆栈跟踪和一些随机代码块,而不了解堆栈跟踪是什么或他们如何使用它。这个问题旨在作为可能需要帮助理解堆栈跟踪值的新手程序员的参考。

采纳答案by Rob Hruska

In simple terms, a stack traceis a list of the method calls that the application was in the middle of when an Exception was thrown.

简单来说,堆栈跟踪是应用程序在抛出异常时所处的方法调用列表。

Simple Example

简单示例

With the example given in the question, we can determine exactly where the exception was thrown in the application. Let's have a look at the stack trace:

通过问题中给出的示例,我们可以准确确定应用程序中抛出异常的位置。让我们看一下堆栈跟踪:

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)

This is a very simple stack trace. If we start at the beginning of the list of "at ...", we can tell where our error happened. What we're looking for is the topmostmethod call that is part of our application. In this case, it's:

这是一个非常简单的堆栈跟踪。如果我们从“at ...”列表的开头开始,我们就可以知道错误发生在哪里。我们正在寻找的是作为我们应用程序一部分的最顶层方法调用。在这种情况下,它是:

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

To debug this, we can open up Book.javaand look at line 16, which is:

为了调试这个,我们可以打开Book.java并查看 line 16,它是:

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

This would indicate that something (probably title) is nullin the above code.

这表明上面的代码中有一些东西(可能titlenull

Example with a chain of exceptions

具有一系列异常的示例

Sometimes applications will catch an Exception and re-throw it as the cause of another Exception. This typically looks like:

有时应用程序会捕获一个异常并将其重新抛出作为另一个异常的原因。这通常看起来像:

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   }

This might give you a stack trace that looks like:

这可能会给您一个堆栈跟踪,如下所示:

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

What's different about this one is the "Caused by". Sometimes exceptions will have multiple "Caused by" sections. For these, you typically want to find the "root cause", which will be one of the lowest "Caused by" sections in the stack trace. In our case, it's:

与此不同的是“由”。有时异常会有多个“由”部分。对于这些,您通常希望找到“根本原因”,这将是堆栈跟踪中最低的“Caused by”部分之一。在我们的例子中,它是:

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

Again, with this exception we'd want to look at line 22of Book.javato see what might cause the NullPointerExceptionhere.

同样,除了这个例外,我们希望查看 line 22ofBook.java以查看可能导致NullPointerExceptionhere 的原因。

More daunting example with library code

更令人生畏的库代码示例

Usually stack traces are much more complex than the two examples above. Here's an example (it's a long one, but demonstrates several levels of chained exceptions):

通常堆栈跟踪比上面的两个例子复杂得多。这是一个示例(它很长,但演示了多个级别的链式异常):

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 this example, there's a lot more. What we're mostly concerned about is looking for methods that are from our code, which would be anything in the com.example.myprojectpackage. From the second example (above), we'd first want to look down for the root cause, which is:

在这个例子中,还有很多。我们最关心的是从我们的代码中寻找方法,这些方法可以是com.example.myproject包中的任何东西。从第二个例子(上面),我们首先要寻找根本原因,即:

Caused by: java.sql.SQLException

However, all the method calls under that are library code. So we'll move up to the "Caused by" above it, and look for the first method call originating from our code, which is:

但是,其下的所有方法调用都是库代码。因此,我们将移至其上方的“Caused by”,并查找源自我们代码的第一个方法调用,即:

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

Like in previous examples, we should look at MyEntityService.javaon line 59, because that's where this error originated (this one's a bit obvious what went wrong, since the SQLException states the error, but the debugging procedure is what we're after).

就像在前面的例子中一样,我们应该看看MyEntityService.javaon line 59,因为这就是这个错误的起源(这个错误有点明显,因为 SQLException 指出了错误,但调试过程是我们所追求的)。

回答by Woot4Moo

To add on to what Rob has mentioned. Setting break points in your application allows for the step-by-step processing of the stack. This enables the developer to use the debugger to see at what exact point the method is doing something that was unanticipated.

补充罗布提到的内容。在您的应用程序中设置断点允许逐步处理堆栈。这使开发人员能够使用调试器查看该方法在什么确切点执行了未预料到的事情。

Since Rob has used the NullPointerException(NPE) to illustrate something common, we can help to remove this issue in the following manner:

由于 Rob 使用NullPointerException(NPE) 来说明一些常见问题,我们可以通过以下方式帮助消除此问题:

if we have a method that takes parameters such as: void (String firstName)

如果我们有一个接受参数的方法,例如: void (String firstName)

In our code we would want to evaluate that firstNamecontains a value, we would do this like so: if(firstName == null || firstName.equals("")) return;

在我们的代码中,我们想要评估firstName包含一个值的值,我们会这样做:if(firstName == null || firstName.equals("")) return;

The above prevents us from using firstNameas an unsafe parameter. Therefore by doing null checks before processing we can help to ensure that our code will run properly. To expand on an example that utilizes an object with methods we can look here:

以上防止我们firstName用作不安全的参数。因此,通过在处理之前进行空检查,我们可以帮助确保我们的代码能够正常运行。要扩展使用带有方法的对象的示例,我们可以在这里查看:

if(dog == null || dog.firstName == null) return;

if(dog == null || dog.firstName == null) return;

The above is the proper order to check for nulls, we start with the base object, dog in this case, and then begin walking down the tree of possibilities to make sure everything is valid before processing. If the order were reversed a NPE could potentially be thrown and our program would crash.

以上是检查空值的正确顺序,我们从基础对象开始,在这种情况下是狗,然后开始沿着可能性树向下走,以确保在处理之前一切都有效。如果顺序颠倒,则可能会抛出 NPE,我们的程序将崩溃。

回答by przemek hertel

There is one more stacktrace feature offered by Throwable family - the possibility to manipulatestack trace information.

Throwable 系列还提供了一项堆栈跟踪功能 -操作堆栈跟踪信息的可能性。

Standard behavior:

标准行为:

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();
    }
}

Stack trace:

堆栈跟踪:

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)

Manipulated stack trace:

操纵的堆栈跟踪:

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();
    }
}

Stack trace:

堆栈跟踪:

Exception in thread "main" java.lang.RuntimeException
    at OtherClass.methodX(String.java:99)
    at OtherClass.methodY(String.java:55)

回答by rghome

The other posts describe what a stack trace is, but it can still be hard to work with.

其他帖子描述了什么是堆栈跟踪,但它仍然很难使用。

If you get a stack trace and want to trace the cause of the exception, a good start point in understanding it is to use the Java Stack Trace Consolein Eclipse. If you use another IDE there may be a similar feature, but this answer is about Eclipse.

如果你得到一个堆栈跟踪,并要跟踪的异常的原因,了解一个很好的起点是使用的Java堆栈跟踪控制台Eclipse中。如果您使用另一个 IDE,可能会有类似的功能,但这个答案是关于 Eclipse 的。

First, ensure that you have all of your Java sources accessible in an Eclipse project.

首先,确保您可以在 Eclipse 项目中访问所有 J​​ava 源代码。

Then in the Javaperspective, click on the Consoletab (usually at the bottom). If the Console view is not visible, go to the menu option Window -> Show Viewand select Console.

然后在Java透视图中,单击Console选项卡(通常在底部)。如果控制台视图不可见,请转到菜单选项Window -> Show View并选择Console

Then in the console window, click on the following button (on the right)

然后在控制台窗口中,单击以下按钮(右侧)

Consoles button

控制台按钮

and then select Java Stack Trace Consolefrom the drop-down list.

然后从下拉列表中选择Java Stack Trace Console

Paste your stack trace into the console. It will then provide a list of links into your source code and any other source code available.

将您的堆栈跟踪粘贴到控制台中。然后它将提供指向您的源代码和任何其他可用源代码的链接列表。

This is what you might see (image from the Eclipse documentation):

这是您可能会看到的(来自 Eclipse 文档的图片):

Diagram from Eclipse documentation

Eclipse 文档中的图表

The most recent method call made will be the topof the stack, which is the top line (excluding the message text). Going down the stack goes back in time. The second line is the method that calls the first line, etc.

由最近的方法调用将是顶部堆叠的,这是顶线(不包括消息文本)。沿着堆栈向下走可以回到过去。第二行是调用第一行的方法,以此类推。

If you are using open-source software, you might need to download and attach to your project the sources if you want to examine. Download the source jars, in your project, open the Referenced Librariesfolder to find your jar for your open-source module (the one with the class files) then right click, select Propertiesand attach the source jar.

如果您使用的是开源软件,则可能需要下载源代码并将其附加到您的项目中以进行检查。下载源 jar,在您的项目中,打开Referenced Libraries文件夹以找到您的开源模块的 jar(带有类文件的那个),然后右键单击,选择Properties并附加源 jar。

回答by Dakkaron

I am posting this answer so the topmost answer (when sorted by activity) is not one that is just plain wrong.

我发布了这个答案,所以最上面的答案(按活动排序时)不是一个完全错误的答案。

What is a Stacktrace?

什么是堆栈跟踪?

A stacktrace is a very helpful debugging tool. It shows the call stack (meaning, the stack of functions that were called up to that point) at the time an uncaught exception was thrown (or the time the stacktrace was generated manually). This is very useful because it doesn't only show you where the error happened, but also how the program ended up in that place of the code. This leads over to the next question:

堆栈跟踪是一个非常有用的调试工具。它显示了在抛出未捕获的异常时(或手动生成堆栈跟踪的时间)的调用堆栈(意思是,在该点之前调用的函数堆栈)。这非常有用,因为它不仅显示错误发生的位置,还显示程序如何在代码的那个位置结束。这就引出了下一个问题:

What is an Exception?

什么是异常?

An Exception is what the runtime environment uses to tell you that an error occurred. Popular examples are NullPointerException, IndexOutOfBoundsException or ArithmeticException. Each of these are caused when you try to do something that is not possible. For example, a NullPointerException will be thrown when you try to dereference a Null-object:

异常是运行时环境用来告诉您发生错误的东西。流行的例子是 NullPointerException、IndexOutOfBoundsException 或 ArithmeticException。当您尝试做一些不可能的事情时,就会导致这些中的每一个。例如,当您尝试取消引用 Null 对象时,将抛出 NullPointerException:

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.

How should I deal with Stacktraces/Exceptions?

我应该如何处理堆栈跟踪/异常?

At first, find out what is causing the Exception. Try googleing the name of the exception to find out, what is the cause of that exception. Most of the time it will be caused by incorrect code. In the given examples above, all of the exceptions are caused by incorrect code. So for the NullPointerException example you could make sure that ais never null at that time. You could, for example, initialise aor include a check like this one:

首先,找出导致异常的原因。尝试用谷歌搜索异常的名称以找出该异常的原因是什么。大多数时候它是由错​​误的代码引起的。在上面给出的示例中,所有异常都是由不正确的代码引起的。因此,对于 NullPointerException 示例,您可以确保当时a永远不会为空。例如,您可以初始化a或包含这样的检查:

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

This way, the offending line is not executed if a==null. Same goes for the other examples.

这样,如果 ,则不会执行违规行a==null。其他示例也是如此。

Sometimes you can't make sure that you don't get an exception. For example, if you are using a network connection in your program, you cannot stop the computer from loosing it's internet connection (e.g. you can't stop the user from disconnecting the computer's network connection). In this case the network library will probably throw an exception. Now you should catch the exception and handleit. This means, in the example with the network connection, you should try to reopen the connection or notify the user or something like that. Also, whenever you use catch, always catch only the exception you want to catch, do not use broad catch statements like catch (Exception e)that would catch all exceptions. This is very important, because otherwise you might accidentally catch the wrong exception and react in the wrong way.

有时您无法确保不会出现异常。例如,如果您在程序中使用网络连接,则无法阻止计算机断开互联网连接(例如,您无法阻止用户断开计算机的网络连接)。在这种情况下,网络库可能会抛出异常。现在您应该捕获异常并处理它。这意味着,在具有网络连接的示例中,您应该尝试重新打开连接或通知用户或类似的事情。此外,无论何时使用 catch,始终只捕获您想要捕获的异常,不要使用宽泛的 catch 语句,例如catch (Exception e)这将捕获所有异常。这非常重要,否则您可能会意外捕获错误的异常并以错误的方式做出反应。

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!")
}

Why should I not use catch (Exception e)?

为什么我不应该使用catch (Exception e)

Let's use a small example to show why you should not just catch all exceptions:

让我们用一个小例子来说明为什么不应该只捕获所有异常:

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;
    }
}

What this code is trying to do is to catch the ArithmeticExceptioncaused by a possible division by 0. But it also catches a possible NullPointerExceptionthat is thrown if aor bare null. This means, you might get a NullPointerExceptionbut you'll treat it as an ArithmeticException and probably do the wrong thing. In the best case you still miss that there was a NullPointerException. Stuff like that makes debugging much harder, so don't do that.

这段代码试图做的是捕获ArithmeticException由 0 可能除法引起的 。但它也捕获NullPointerExceptionifabare抛出的可能null。这意味着,您可能会得到一个NullPointerException但您会将其视为 ArithmeticException 并且可能会做错事。在最好的情况下,您仍然会错过 NullPointerException。这样的事情会使调试变得更加困难,所以不要这样做。

TLDR

TLDR

  1. Figure out what is the cause of the exception and fix it, so that it doesn't throw the exception at all.
  2. If 1. is not possible, catch the specific exception and handle it.

    • Never just add a try/catch and then just ignore the exception! Don't do that!
    • Never use catch (Exception e), always catch specific Exceptions. That will save you a lot of headaches.
  1. 找出异常的原因并修复它,以便它根本不会抛出异常。
  2. 如果 1. 不可能,则捕获特定异常并处理它。

    • 永远不要只添加一个 try/catch 然后忽略异常!不要那样做!
    • 永远不要使用catch (Exception e),总是捕获特定的异常。这将为您省去很多麻烦。

回答by Eugene S

Just to add to the other examples, there are inner(nested) classesthat appear with the $sign. For example:

只是为了添加到其他示例中,有带有符号的内部(嵌套)类$。例如:

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();
    }
}

Will result in this stack trace:

将导致此堆栈跟踪:

Exception in thread "main" java.lang.RuntimeException
        at Test.privateMethod(Test.java:4)
        at Test.access
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)
0(Test.java:1) at Test.run(Test.java:10) at Test.main(Test.java:13)

回答by Kevin Li

To understand the name: A stack trace is a a list of Exceptions( or you can say a list of "Cause by"), from the most surface Exception(e.g. Service Layer Exception) to the deepest one (e.g. Database Exception). Just like the reason we call it 'stack' is because stack is First in Last out (FILO), the deepest exception was happened in the very beginning, then a chain of exception was generated a series of consequences, the surface Exception was the last one happened in time, but we see it in the first place.

要理解这个名称:堆栈跟踪是异常列表(或者您可以说是“原因”列表),从最表面的异常(例如服务层异常)到最深的异常(例如数据库异常)。就像我们称它为“堆栈”的原因一样,因为堆栈是先进后出(FILO),最深的异常发生在最开始的时候,然后产生一连串的异常一系列后果,表面的异常是最后一个一个及时发生,但我们首先看到它。

Key 1:A tricky and important thing here need to be understand is : the deepest cause may not be the "root cause", because if you write some "bad code", it may cause some exception underneath which is deeper than its layer. For example, a bad sql query may cause SQLServerException connection reset in the bottem instead of syndax error, which may just in the middle of the stack.

关键1:这里需要理解的一个棘手而重要的事情是:最深层次的原因可能不是“根本原因”,因为如果你写了一些“坏代码”,它可能会导致一些比它更深的异常。例如,错误的 sql 查询可能会导致 bottem 中的 SQLServerException 连接重置而不是 Syndax 错误,后者可能只是在堆栈的中间。

-> Locate the root cause in the middle is your job.enter image description here

->找到中间的根本原因是你的工作。在此处输入图片说明

Key 2:Another tricky but important thing is inside each "Cause by" block, the first line was the deepest layer and happen first place for this block. For instance,

关键 2:另一个棘手但重要的事情是在每个“原因”块内,第一行是最深的层,并且发生在该块的第一位。例如,

##代码##

Book.java:16 was called by Auther.java:25 which was called by Bootstrap.java:14, Book.java:16 was the root cause. Here attach a diagram sort the trace stack in chronological order. enter image description here

Book.java:16 被 Bootstrap.java:14 调用的 Auther.java:25 调用,Book.java:16 是根本原因。这里附上一个图表,按时间顺序对跟踪堆栈进行排序。 在此处输入图片说明