如何在 getter 链中跟踪 NullPointerException

如果我在这样的调用中得到一个NullPointerException:

someObject.getSomething().getSomethingElse().
    getAnotherThing().getYetAnotherObject().getValue();

我得到一个相当无用的异常文本,如:

Exception in thread "main" java.lang.NullPointerException
at package.SomeClass.someMethod(SomeClass.java:12)

我发现很难找出哪个调用实际上返回了null,经常发现自己将代码重构为如下所示:

Foo ret1 = someObject.getSomething();
Bar ret2 = ret1.getSomethingElse();
Baz ret3 = ret2.getAnotherThing();
Bam ret4 = ret3.getYetAnotherOject();
int ret5 = ret4.getValue();

然后等待一个更具描述性的NullPointerException,告诉我要查找哪一行。

你们中的一些人可能会争辩说,连接getters是不好的风格,无论如何都应该避免,但我的问题是:我可以在不更改代码的情况下找到错误吗?

提示:我正在使用eclipse,我知道调试器是什么,但我无法弄清楚如何将其应用于问题。

我对答案的结论是:
有些答案告诉我,我不应该一个接一个地链接getter,有些答案显示了如果我不服从这个建议,如何调试我的代码。

我接受了一个答案,它教会了我何时链接获取器:

  • 如果它们不能返回 null,请根据需要将它们链接起来。无需检查!=null,无需担心NullPointerExceptions(请注意,链接仍然违反了Demeter定律,但我可以忍受这一点)
  • 如果它们可能返回 null,则永远不要,永远不要链接它们,并对每个可能返回 null 的值执行检查

这使得任何关于实际调试的好建议都毫无用处。


答案 1

NPE是Java中最无用的例外。它似乎总是懒惰地实现,并且从不确切地告诉导致它的原因,即使像“类x.y.Z为空”这样简单,也会对调试这种情况有很大帮助。

无论如何,在这些情况下,我发现找到NPE抛出器的唯一好方法是以下重构:

someObject.getSomething()
          .getSomethingElse()
          .getAnotherThing()
          .getYetAnotherObject()
          .getValue();

你有它,现在NPE指向正确的线,从而正确的方法,抛出实际的NPE。不像我想要的那么优雅的解决方案,但它有效。


答案 2

答案取决于你如何看待(合同)你的getters。如果它们可能返回,您应该每次都检查返回值。如果 getter 不应该返回,getter 应该包含一个检查并抛出一个异常 (?) 而不是返回 ,你承诺永远不会返回。堆栈跟踪将指向确切的 getter。您甚至可以将 getter 发现的意外状态放在异常消息中。nullnullIllegalStateExceptionnull