什么是空指针异常 ( java.lang.NullPointerException) 以及导致它们的原因?
java.lang.NullPointerException
可以使用哪些方法/工具来确定原因,以便阻止异常导致程序过早终止?
当您声明一个引用变量(即一个对象)时,您实际上是在创建一个指向对象的指针。考虑以下代码,您在其中声明了一个原始类型的变量int:
int
int x; x = 10;
在这个例子中,变量x是一个int,Java 会0为你初始化它。当您10在第二行分配 的值时,您的值将10写入 引用的内存位置x。
x
0
10
但是,当您尝试声明引用 类型 时,会发生不同的事情。采取以下代码:
Integer num; num = new Integer(10);
第一行声明了一个名为 的变量num,但它实际上还没有包含原始值。相反,它包含一个指针(因为类型是Integer引用类型)。由于您还没有说要指向什么,Java 将它设置为null,这意味着“ 我没有指向 任何东西 ”。
num
Integer
null
在第二行中,new关键字用于实例化(或创建)类型为 的对象Integer,并将指针变量num分配给该Integer对象。
new
( NullPointerExceptionNPE) 发生在您声明一个变量但没有创建对象并将其分配给变量之前尝试使用变量的内容(称为 解引用 )。所以你指向的东西实际上并不存在。
NullPointerException
解引用通常发生在.用于访问方法或字段,或[用于索引数组时。
.
[
如果您在创建对象num 之前 尝试取消引用,则会得到一个NullPointerException. 在最琐碎的情况下,编译器会发现问题并让您知道“” num may not have been initialized,但有时您可能会编写不直接创建对象的代码。
num may not have been initialized
例如,您可能有如下方法:
public void doSomething(SomeObject obj) { // Do something to obj, assumes obj is not null obj.myMethod(); }
在这种情况下,您不是在创建 object obj,而是假设它是在doSomething()调用方法之前创建的。请注意,可以像这样调用该方法:
obj
doSomething()
doSomething(null);
在这种情况下,objis null,并且该语句obj.myMethod()将抛出NullPointerException。
obj.myMethod()
如果该方法打算像上述方法那样对传入的对象执行某些操作,则抛出 是合适的,NullPointerException因为这是程序员错误,程序员将需要该信息进行调试。
除了NullPointerException作为方法逻辑的结果抛出 s 之外,您还可以通过在方法null开头附近添加类似以下内容来检查方法参数的值并显式抛出 NPE:
// Throws an NPE with a custom error message if obj is null Objects.requireNonNull(obj, "obj must not be null");
请注意,在错误消息中清楚地说明 哪个 对象不能是很有帮助的null。验证这一点的好处是 1) 您可以返回自己更清晰的错误消息,以及 2) 对于您知道的其余方法,除非obj重新分配,否则它不为 null 并且可以安全地取消引用。
或者,可能存在方法的目的不仅仅是对传入的对象进行操作的情况,因此可以接受空参数。在这种情况下,您需要检查 空参数 并采取不同的行为。您还应该在文档中解释这一点。例如,doSomething()可以写成:
/** * @param obj An optional foo for ____. May be null, in which case * the result will be ____. */ public void doSomething(SomeObject obj) { if(obj == null) { // Do something } else { // Do something else } }
现在 Java 14 添加了一个新的语言特性来显示 NullPointerException 的根本原因。自 2006 年以来,此语言功能已成为 SAP 商业 JVM 的一部分。
在 Java 14 中,以下是示例 NullPointerException 异常消息:
在线程“main”中 java.lang.NullPointerException:无法调用“java.util.List.size()”,因为“list”为空