我对NullPointerException有一个非常奇怪的问题。代码示例如下:
...
... public String[] getParams(...) {
... ...
... ...
143 return new String[] {
144 getUserFullName(),
145 StringUtil.formatDate(sent),
. tiltu,
. StringUtil.initCap(user.getName()),
. vuosi.toString(),
. asiatyyppi[0] + " " + lisatiedot[0],
. asiatyyppi[1] + " " + lisatiedot[1],
. alaviitteet[0],
152 alaviitteet[1]};
153 }
现在,我遇到了一个有堆栈跟踪的生产问题:
java.lang.NullPointerException
at package.EmailService.getParams(EmailService.java:143)
...
我自己无法生成那种堆栈跟踪。这可能是一些环境问题,由于某种原因,行号不匹配。如果我对任何变量堆栈跟踪点的空引用指向该特定行,但从不对第143行。
但我想问的是:是否有可能在第143行产生NullPointerException?
答案 0 :(得分:5)
考虑定义新String
数组的原始代码:
return new String[] {
getUserFullName(),
StringUtil.formatDate(sent),
tiltu,
StringUtil.initCap(user.getName()),
vuosi.toString(),
asiatyyppi[0] + " " + lisatiedot[0],
asiatyyppi[1] + " " + lisatiedot[1],
alaviitteet[0],
alaviitteet[1]};
}
如果内联数组的任何元素应该触发NullPointerException
,则JVM会将异常解释为定义开始的行。换句话说,JVM将以上代码视为:
return new String[] { getUserFullName(), StringUtil.formatDate(sent), tiltu, StringUtil.initCap user.getName()), vuosi.toString(), asiatyyppi[0] + " " + lisatiedot[0], asiatyyppi[1] + " " + lisatiedot[1], alaviitteet[0], alaviitteet[1]}; }
一切都在一条线上。
如果你真的想在这里处理NullPointerException
,你应该在实例化之外定义变量。
答案 1 :(得分:5)
堆栈跟踪中的行号来自类文件中的LineNumberTable属性。 (See JVM specification)
为子表达式输出正确的行号是没有问题的 - 所有编译器必须做的就是说从字节码索引x到y,与源代码行z有对应关系。
但是直到并包括Java 1.7,编译器中存在一个错误,修正在1.8:
https://bugs.openjdk.java.net/browse/JDK-7024096
问题描述:仅在编译代码中可以使用 具有开头语句的行号。当声明正在使用时 方法链接或其他“流畅的接口”风格API是单一的 语句可以跨越数十行并包含数百个方法 调用
目前,任何这些方法中的异常抛出都会 有封闭声明第一行的亚麻布 使调试哪个方法调用有问题非常困难。
linnumbertable应该为每个方法都有正确的行号 调用
-
BT2:评价
解决这个问题似乎很简单,但最终有点危险 jdk7开发周期,目标是jdk8。
所以在1.7中,你会得到这些子表达式的错误报告行号(如果它们出现在同一个方法中 - 如果你在子表达式中调用了另一个方法,而另一个方法导致了NullPointerException,你会看到它在那里报道 - 这可能是为什么这个bug并不总是一个大问题)
解决此问题的一种方法是使用Java 8编译器编译源代码,并使用标志javac -source 1.7 -target 1.7
。但是将prod环境升级到1.8会更好更安全。