为什么Java不告诉你哪个指针为null?

kpo*_*zin 27 java debugging nullpointerexception

我一直想知道为什么JVM不会告诉你在抛出时哪个指针(或更确切地说,哪个变量)为null NullPointerException.

行号不够具体,因为违规行通常可能包含许多可能导致错误的变量.

是否有任何编译器或JVM标志可以使这些异常消息更有用?

Mic*_*hue 49

这是因为当没有名称可用时,取消引用总会发生.该值将加载到操作数堆栈上,然后传递给解除引用的JRE操作码之一.但是,操作数堆栈没有与空值关联的名称.它只是'null'.使用一些聪明的运行时跟踪代码,可以派生一个名称,但这会增加有限值的开销.

因此,没有JRE选项可以为空指针异常打开额外信息.

在此示例中,引用存储在本地插槽1中,该插槽映射到本地变量名称.但是取消引用发生在invokevirtual指令中,它只在堆栈上看到'null'值,然后抛出异常:

15 aload_1
16 invokevirtual #5 
Run Code Online (Sandbox Code Playgroud)

同样有效的是数组加载后跟一个取消引用,但在这种情况下,没有名称可以映射到'null'值,只是一个索引关闭另一个值.

76 aload    5
78 iconst_0
79 aaload
80 invokevirtual #5
Run Code Online (Sandbox Code Playgroud)

你不能静态地为每个指令分配名称 - 这个例子产生很多字节码,但是你可以看到解除引用指令将接收到objA或objB,你需要动态地跟踪它以报告正确的,因为两个变量都流向相同的解引用指令:

(myflag ? objA : objB).toString()
Run Code Online (Sandbox Code Playgroud)

  • +1对于实际的解释而不是"如果你以正确的方式编写代码",这不会发生在你身上. (7认同)
  • JVM应该能够告诉我们哪个指令导致NPE,并且我认为这仍然非常有用,例如,如果表达式"abcdef"导致NPE. (3认同)

Sam*_*ell 12

一旦你JIT代码,它只是本机指针数学,如果本机代码中的任何指针为null,它会抛出异常.将组件反转回原始变量会产生破坏性的性能影响,并且考虑到JIT将生成的代码优化到不同的级别,通常甚至都不可能.

  • @Michael:JIT在本机代码生成期间跟踪行号.它不会以高于(子表达式等)的分辨率进行跟踪. (2认同)