什么是 Null Pointer Exceptions ( java.lang.NullPointerException
) 是什么原因造成的?
可以使用哪些方法/工具来确定原因,以便阻止异常导致程序过早终止?
当你声明一个引用变量(即一个对象)时,你实际上是在创建一个指向一个对象的指针。 考虑以下代码,您在其中声明了一个原始类型的变量 int
:
int x; x = 10;
在本例中,变量 x
是 int
Java 会为您将其初始化为 0
。 当你在第二行分配值 10
时,你的值 10
将写入 x
引用的内存位置。
但是,当你尝试声明引用类型时,会发生不同的事情。 采取以下代码:
Integer num; num = new Integer(10);
第一行声明了一个名为 num
, 但它实际上并不包含原始值。相反,它包含一个指针(因为类型是整数,它是一个引用类型)。 由于您还没有说要指向什么,Java 将其设置为 null
, 这意味着 “ I am pointing to nothing “.
在第二行中, new
关键字用于实例化(或创建)一个 Integer
类型的对象,并将指针变量 num
is 分配给该 Integer
对象。
NullPointerException
(NPE) 发生在您声明一个变量但未创建对象并将其分配给该变量之前尝试使用该变量的内容(称为取消引用)。 所以你指向的东西实际上并不存在。
取消引用通常发生在使用 .
访问方法或字段,或使用 [
索引数组。
如果你在创建对象 之前 尝试取消引用 num
则会收到 NullPointerException
. 在最琐碎的情况下,编译器会发现问题并让你知道 “ num 可能尚未初始化 num may not have been initialized
,” 但有时你可能会编写不直接创建对象的代码。
例如,你可能有如下方法:
public void doSomething(SomeObject obj) { // Do something to obj, assumes obj is not null obj.myMethod(); }
在这种情况下,你不是在创建对象 obj
, 而是假设它是在调用 doSomething()
方法之前创建的。. 注意,可以像这样调用该方法:
doSomething(null);
在这种情况下, obj
为 null
, 并且语句 obj.myMethod()
将抛出 NullPointerException
.
如果该方法打算像上述方法那样对传入的对象执行某些操作,则抛出 NullPointerException
是合适的,因为这是程序员错误,程序员将需要该信息进行调试。
除了由于方法的逻辑而引发的 NullPointerException之外,您还可以检查方法参数的
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 并且可以安全地取消引用。
或者,可能存在方法的目的不仅仅是对传入的对象进行操作的情况,因此可以接受空参数。您需要检查 null parameter 并采取不同的行为。 您还应该在文档中解释这一点。 例如, 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 } }