有时当我运行我的应用程序时,它会给我一个看起来像这样的错误:
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)
人们将此称为“堆栈跟踪”。 什么是堆栈跟踪? 它能告诉我关于程序中发生的错误的什么信息?
关于这个问题——我经常看到新手程序员“遇到错误”的问题,他们只是简单地粘贴他们的堆栈跟踪和一些随机代码块,而不了解堆栈跟踪是什么或他们如何使用它。此问题旨在为可能需要帮助以了解堆栈跟踪的价值的新手程序员提供参考。
原文由 Rob Hruska 发布,翻译遵循 CC BY-SA 4.0 许可协议
简单来说, 堆栈跟踪 是应用程序在抛出异常时所处的方法调用的列表。
简单例子
通过问题中给出的示例,我们可以准确地确定应用程序中抛出异常的位置。让我们看一下堆栈跟踪:
这是一个非常简单的堆栈跟踪。如果我们从“at …”列表的开头开始,我们就可以知道我们的错误发生在哪里。我们正在寻找的是属于我们应用程序一部分的 最顶层 方法调用。在这种情况下,它是:
要调试它,我们可以打开
Book.java
并查看行16
,它是:这表明上面的代码中的某些东西(可能是
title
)是null
。具有异常链的示例
有时应用程序会捕获异常并将其作为另一个异常的原因重新抛出。这通常看起来像:
这可能会给你一个看起来像这样的堆栈跟踪:
这个的不同之处在于“Caused by”。有时异常会有多个“原因”部分。对于这些,您通常希望找到“根本原因”,这将是堆栈跟踪中最低的“原因”部分之一。在我们的例子中,它是:
同样,除了这个例外,我们想看看
22
的Book.java
行,看看是什么导致了NullPointerException
。库代码的更令人生畏的例子
通常堆栈跟踪比上面的两个例子复杂得多。这是一个示例(它很长,但演示了几个级别的链式异常):
在这个例子中,还有更多。我们最关心的是从 我们的代码 中寻找方法,这些方法可以是
com.example.myproject
包中的任何内容。从第二个示例(上面)中,我们首先要查找根本原因,即:但是,其下的所有方法调用都是库代码。所以我们将 移动 到它 上面的“Caused by” ,并在那个“Caused by”块中,查找 源自我们代码的第一个方法调用,它是:
与前面的示例一样,我们应该查看
MyEntityService.java
在线59
,因为这是此错误的来源(这个有点明显出了什么问题,因为 SQLException 指出了错误,但是调试过程就是我们所追求的)。