我一直想知道为什么JVM不会告诉你哪个指针(或者更确切地说哪个变量)在抛出NullPointerException
时为空。为什么Java不告诉你哪个指针是空的?
行号不够具体,因为违规行通常可能包含许多可能导致错误的变量。
是否有任何编译器或JVM标志使这些异常消息更有用?
我一直想知道为什么JVM不会告诉你哪个指针(或者更确切地说哪个变量)在抛出NullPointerException
时为空。为什么Java不告诉你哪个指针是空的?
行号不够具体,因为违规行通常可能包含许多可能导致错误的变量。
是否有任何编译器或JVM标志使这些异常消息更有用?
这是因为当没有可用的名称时总是会发生取消引用。该值被加载到操作数堆栈中,然后传递给其中一个解引用它的JRE操作码。但是,操作数堆栈没有与空值关联的名称。它只有'空'。通过一些聪明的运行时跟踪代码,可以派生出一个名称,但这会增加开销和限制值。
因此,没有JRE选项会打开空指针异常的额外信息。
在此示例中,引用存储在本地插槽1中,该插槽映射到本地变量名称。但解除引用发生在invokevirtual指令,该指令只看到堆栈上的“空”值,然后将引发异常:
15 aload_1
16 invokevirtual #5
同样有效。将数组负载后跟一个间接引用,但是在这种情况没有名称可以映射到'空'值,只是一个索引而不是另一个值。
76 aload 5
78 iconst_0
79 aaload
80 invokevirtual #5
不能静态分配的名称给每个指令会 - 这个例子中会产生大量的字节码的,但你可以看到,取消引用指令将接受或objA或objB,你需要跟踪此动态报告是正确的,因为这两个变量流向相同的取消引用指令:
(myflag ? objA : objB).toString()
一旦你JIT的代码,它只是本地指针数学,并且如果本地代码中的任何指针为null它会引发异常。如果将该组件还原为原始变量,并且考虑到JIT将生成的代码优化为不同的级别,这往往不可能发生破坏性的性能影响。
如果您将行分成多行而不是在一行上进行多个方法调用,或者如果您在该行上设置断点并通过调试器遍历行,则可以很容易地确定哪些引用非常容易。
如果
行号是不够具体 ,因为出错的行往往能 包含可能 造成的错误很多的变化。
话,我建议:
NullPointerException
- 产生值的临时变量。不幸的是,这只是Java的工作方式。
如果这是“你的”代码,然后简单地分配富之后添加片段喜欢
if (foo == null) {
throw new NullPointerException("foo == null");
}
。如果foo是一个参数,那么在方法体的开始处立即检查,然后抛出IllegalArgumentException。
这应该可以帮助你澄清问题。
您可以在空指针异常在Eclipse中调试获得异常的具体原因时,添加一个断点。
作为一名专业的Java开发人员,这对于我来说从未成为一个问题。如果在一行中有很多引用可能为空,那么可能是时候将其分解为多行。 – MattC 2009-07-22 22:06:23
@mattc,你从来没有与其他人的图书馆代码工作? – 2009-07-22 22:51:41
@MATC:当你需要在长if-else-if块的中间条件下调用具有多个参数的函数时,经常会出现这种情况。将它分成多行意味着将会在if语句的顶部之前声明一堆虚拟变量。我会说在大多数情况下,这在代码可读性和风格方面会更成问题。 – kpozin 2009-07-23 14:28:05