什么是空指针异常 ( java.lang.NullPointerException
) 以及导致它们的原因是什么?
可以使用哪些方法/工具来确定原因,以便阻止异常导致程序过早终止?
原文由 Ziggy 发布,翻译遵循 CC BY-SA 4.0 许可协议
什么是空指针异常 ( java.lang.NullPointerException
) 以及导致它们的原因是什么?
可以使用哪些方法/工具来确定原因,以便阻止异常导致程序过早终止?
原文由 Ziggy 发布,翻译遵循 CC BY-SA 4.0 许可协议
NullPointerException
s 是当您尝试使用指向内存中任何位置(空)的引用时发生的异常,就好像它在引用一个对象一样。在空引用上调用方法或尝试访问空引用的字段将触发 NullPointerException
。这些是最常见的,但 NullPointerException
javadoc 页面上列出了其他方式。
可能是我想出的最快的示例代码来说明 NullPointerException
是:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
On the first line inside main
, I’m explicitly setting the Object
reference obj
equal to null
.这意味着我有一个引用,但它没有指向任何对象。之后,我尝试通过在其上调用方法来将引用视为指向对象。这导致 NullPointerException
因为在引用指向的位置没有要执行的代码。
(这是一个技术问题,但我认为值得一提:指向 null 的引用与指向无效内存位置的 C 指针不同。空指针实际上不指向 _任何地方_,这与指向一个恰好无效的位置。)
原文由 Bill the Lizard 发布,翻译遵循 CC BY-SA 4.0 许可协议
15 回答8.4k 阅读
8 回答6.2k 阅读
1 回答4k 阅读✓ 已解决
3 回答2.2k 阅读✓ 已解决
2 回答3.1k 阅读
2 回答3.8k 阅读
3 回答1.7k 阅读✓ 已解决
Java中有两种主要的变量类型:
Primitives :包含数据的变量。如果要操作原始变量中的数据,可以直接操作该变量。按照约定,原始类型以小写字母开头。例如
int
或char
类型的变量是原语。_参考_:包含
Object
的内存地址的变量,即 引用Object
的变量。如果您想操作引用变量所引用的Object
您必须 取消引用 它。取消引用通常需要使用.
来访问方法或字段,或使用[
来索引数组。按照惯例,引用类型通常用以大写开头的类型表示。例如Object
类型的变量是引用。考虑以下代码,您在其中声明了一个 原始 类型的变量
int
并且不初始化它:这两行将导致程序崩溃,因为没有为
x
指定值,我们正在尝试使用x
的值来指定y
。所有原语都必须在操作之前初始化为可用值。现在事情变得有趣了。 引用 变量可以设置为
null
这意味着“ 我没有引用 任何内容”。如果您以这种方式显式设置它,或者引用变量未初始化并且编译器没有捕获它(Java 将自动将该变量设置为null
null
)。如果引用变量由您或通过 Java 自动设置为 null,并且您尝试 取消引用 它,您会得到
NullPointerException
。NullPointerException
(NPE) 通常发生在您声明变量但未创建对象并将其分配给变量之前尝试使用变量的内容时。所以你有一个实际不存在的东西的参考。采取以下代码:
第一行声明了一个名为
num
的变量,但它实际上并不包含参考值。由于您还没有说要指向什么,Java 将其设置为null
。在第二行中,
new
关键字用于实例化(或创建)类型为Integer
的对象,并将引用变量num
分配给该对象Integer
对象。如果您在创建对象 之前 尝试取消引用
num
您会得到一个NullPointerException
。在最琐碎的情况下,编译器会发现问题并让您知道“num may not have been initialized
”,但有时您可能会编写不直接创建对象的代码。例如,您可能有如下方法:
在这种情况下,您不是在创建对象
obj
,而是假设它是在调用doSomething()
方法之前创建的。请注意,可以像这样调用该方法:在这种情况下,
obj
是null
,并且语句obj.myMethod()
将抛出NullPointerException
.如果该方法打算像上述方法那样对传入的对象执行某些操作,则抛出
NullPointerException
是合适的,因为这是一个程序员错误,程序员将需要该信息进行调试。除了
NullPointerException
作为方法逻辑的结果抛出之外,您还可以检查null
值的方法参数,并通过在开头附近添加类似以下内容来显式抛出 NPE一个方法:请注意,在错误消息中清楚地说明 哪个 对象不能是
null
会很有帮助。验证这一点的好处是 1) 您可以返回自己更清晰的错误消息,以及 2) 对于您知道的其余方法,除非重新分配obj
,否则它不为空并且可以安全地取消引用。或者,可能存在方法的目的不仅仅是对传入的对象进行操作的情况,因此可以接受空参数。在这种情况下,您需要检查 空参数 并采取不同的行为。您还应该在文档中解释这一点。例如,
doSomething()
可以写成:最后, 如何使用 Stack Trace 查明异常和原因
带有查找错误的声纳可以检测 NPE。 sonar能否动态捕捉JVM引起的空指针异常
现在 Java 14 添加了一个新的语言特性来显示 NullPointerException 的根本原因。自 2006 年以来,此语言功能已成为 SAP 商业 JVM 的一部分。
在 Java 14 中,以下是示例 NullPointerException 异常消息:
导致
NullPointerException
发生的情况列表以下是 Java 语言规范中直接提到的所有出现
NullPointerException
的情况:throw null;
synchronized (someNullReference) { ... }
NullPointerException
如果其操作数之一是盒装空引用NullPointerException
。super
会引发NullPointerException
。如果您感到困惑,这是在谈论合格的超类构造函数调用:使用
for (element : iterable)
循环遍历空集合/数组。switch (foo) { ... }
(无论是表达式还是语句)可以在foo
为空时抛出NullPointerException
—。foo.new SomeInnerClass()
NullPointerException
当foo
为空时抛出 —。Method references of the form
name1::name2
orprimaryExpression::name
throws aNullPointerException
when evaluated whenname1
orprimaryExpression
evaluates to null .这里 JLS 的一条注释说,
someInstance.someStaticMethod()
不会抛出 NPE,因为someStaticMethod
是静态的,但是someInstance::someStaticMethod
仍然抛出 NPE!\* 请注意,JLS 可能也 间接 提到了很多关于 NPE 的内容。