1

在此示例代码NullPointerException中,第 4 行抛出了 a。

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()[in dev environment] 中扔了一个 NPE,以将堆栈跟踪与神秘的 live 进行比较。它确实具有预期的额外堆栈帧。

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)
4

2 回答 2

6

我会给你一些理论上的选择:

  1. 这可能是一件普通的事情,例如报告错误的行号。例如,由于二进制代码和您正在查看的源代码版本不同;
  2. 异常可能发生在其他地方,但您会看到一个被切断的堆栈跟踪。这可能是由于一些中间代码弄乱了堆栈跟踪(这不需要魔法,只是普通的 Java),或者日志框架可能偶尔会弄乱它;
  3. 你在 JRockit 中遇到了一个实际的错误,可能是它的 JIT。例如,可能有一些当地人在进行有效的清算,但发生了乱序。

我的建议:在循环中插入一条日志语句,但在doGenerate调用上方。您也可以显式记录generator != null. 这将帮助您消除除最奇怪的解释之外的任何解释。

于 2013-06-04T08:46:02.503 回答
0

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

于 2017-11-17T15:12:04.113 回答