返回new []时出现NullPointerException

时间:2015-05-11 05:40:41

标签: java nullpointerexception

我对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?

2 个答案:

答案 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会更好更安全。