不可能的NPE被抛出(java)

时间:2013-06-04 08:40:56

标签: java nullpointerexception

在此示例代码中,第4行正在抛出NullPointerException

1. private <O,T> void generate(Suggestion suggestion, GeneratorFactory<O, T> generatorFactory) {
2.     final Generator<O, T> generator = generatorFactory.getGenerator(suggestion);
3.     while (generator.hasNext()) {
4.         generator.doGenerate();
5.     }
6.     // post-generate stuff here
7. }

它只是偶尔发生,但它在实时服务器上发生了几次,所以它不是某种“鬼”错误 - 它肯定需要修复。


堆栈追踪:

java.lang.NullPointerException
    at package.SuggestionServiceImpl.generate(SuggestionServiceImpl.java:4)

GeneratoryFactory的代码:

@Override
public synchronized Generator<O, T> getGenerator(final Suggestion suggestion) {
    Generator<O, T> generator = generators.get(suggestion.getId());
    if (generator == null) {
        generator = construct(suggestion); // calls `new Generator()`
        generators.put(suggestion.getId(), generator);
    }
    return generator;
}

我很困惑:

  • 为什么我们不在第3行的'if'语句中获取NPE,如果generator为空?
  • 如果异常来自哪里,堆栈跟踪如何从第4行开始,而不是从doGenerate()内的一行开始? (doGenerate()的内部是冗长而复杂的 - NPE可能从这里开始,但为什么没有堆栈跟踪?)

更新

作为一个实验测试,我故意在doGenerate() [在开发环境]中抛出一个NPE来比较堆栈跟踪和神秘的活动跟踪。它确实具有预期的额外堆栈帧。

java.lang.NullPointerException: DELIBERATE TEST EXCEPTION
    at package.Generator.doGenerate(Generator.java:71)
    at package.SuggestionServiceImpl.generate(SuggestionServiceImpl.java:4)

运行时JVM是:

java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Oracle JRockit(R) (build R28.1.4-7-144370-1.6.0_26-20110617-2130-linux-x86_64, compiled mode)

2 个答案:

答案 0 :(得分:6)

我会给你一些理论选择:

  1. 它可能是一个平凡的事情,如报告错误的行号。例如,由于二进制代码的不同版本和您正在查看的源代码;
  2. 异常可能发生在其他地方,但你看到一个被切断的堆栈跟踪。这可能是由于一些干扰代码搞乱堆栈跟踪(没有神奇的东西,只是简单的Java),或者日志框架可能偶尔弄乱它;
  3. 你正在点击JRockit中的一个实际错误,可能是它的JIT。例如,可能会有一些当地人清除,这种情况无序发生。
  4. 我的建议:在循环中插入一条日志语句,但在doGenerate调用之上。您还可以显式记录generator != null的结果。这将帮助您消除任何但最奇怪的解释。

答案 1 :(得分:0)

我遇到过类似的问题。它看起来像JUnit(或JVM)以错误的方式截断堆栈跟踪。在try / catch中包装整个测试方法并使用Exception.printStackTrace()显示了NPE的真正来源,而不是“不可能”的位置。

相关问题