找出以编程方式抛出NullPointerException的变量

Hec*_*ret 23 java debugging nullpointerexception

我知道我可以使用这些技术找出Java中的变量是否为null:

  • 如果(var==null)- >太多的工作
  • try { ... } catch (NullPointerException e) { ...} - >它告诉我什么行抛出异常
  • 使用调试器 - >手动,太慢了

考虑以下代码行:

if (this.superSL.items.get(name).getSource().compareTo(VIsualShoppingList.Source_EXTRA)==0)  {
Run Code Online (Sandbox Code Playgroud)

我想知道是否有一种通用的方法来以编程方式找出哪个变量(不仅仅是行)在某个代码区域中抛出NullPointerException.在这个例子中,知道这一点

Asa*_*aph 28

因为即使没有涉及变量也可能导致空指针异常:

throw new NullPointerException();
Run Code Online (Sandbox Code Playgroud)

我不得不说,没有通用的方法可以将空指针异常固定到特定变量.

你最好的选择是尽可能少地在每一行上添加语句,以便明显是什么导致空指针异常.考虑在问题中重构代码,看起来像这样:

List items = this.superSL.items;
String name = items.get(name);
String source = name.getSource();
if (source.compareTo(VIsualShoppingList.Source_EXTRA) == 0)  {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

这是更多的代码行.但它也更具可读性和可维护性.


Von*_*onC 11

您可能会考虑,正如这里宣布的,JDK 14 应该包含JEP 358

JEP 358:有用的 NullPointerExceptions

假设在这段代码中出现了一个 NPE:

a.b.c.i = 99;
Run Code Online (Sandbox Code Playgroud)

文件名和行号不能准确指出哪个变量为空。
是不是a还是bc

数组访问和分配也会出现类似的问题。假设在这段代码中出现了一个 NPE:

a[i][j][k] = 99;
Run Code Online (Sandbox Code Playgroud)

文件名和行号不能准确指出哪个数组组件为空。
是不是a还是a[i]a[i][j]

描述:

如果更复杂的语句a.b.c.i = 99;抛出 NPE,消息将剖析该语句并通过显示导致空值的完整访问路径来查明原因:

Exception in thread "main" java.lang.NullPointerException: 
        Cannot read field "c" because "a.b" is null
    at Prog.main(Prog.java:5)
Run Code Online (Sandbox Code Playgroud)

再次:使用 JDK 14 进行测试。


Holger在评论中补充道:

对于 expression a[i][j][k],也有可能i, j, 或k具有类型Integer并且为空,因此拆箱失败。

在现实生活场景中,右边的表达=也可能具有 NPE 的潜力。

我试过 jdk-14.0.1

有用; 它产生一条消息,如

Cannot invoke "java.lang.Integer.intValue()" because "i" is null then.
Run Code Online (Sandbox Code Playgroud)

当方法在没有调试信息的情况下被编译时,它会使用类似“ <local8>”的东西而不是“ i”,但这是不可避免的。


Ber*_*t F 6

对不起,不,没有一种简单的编程方法来确定哪个变量或方法调用是异常的来源.您可以使用面向方面编程(AOP)之类的东西,例如AspectJ,但这不是语言所固有的,并且通常不会仅仅为了调试目的而合并到程序中.

  • if (var==null) -> too much work
  • try { } catch() { }
  • Debugger

我知道你不想听到这个,但这些只是做生意的成本.

if (this.superSL.items.get(name).getSource().compareTo(VIsualShoppingList.Source_EXTRA)==0)  {
Run Code Online (Sandbox Code Playgroud)

看到如此多的串联方法调用是不寻常的.我相信你最好的选择就是养成更多打破这些的习惯 - 每行不要低至1个电话,但要少于此.为什么?

1)Correctness- 这些调用中的一个调用返回null是否有效?如果是这样,你应该将其分解,测试并适当地处理它.

2)Understandability- 未来的维护者(包括未来的你)将更容易理解你是否有中间的,命名良好的变量来帮助澄清这一行上发生的事情.

3)Efficiency- 通常当你深入到图形中(将一系列方法调用串联起来)时,你可能需要稍后回到那里.在中间变量中捕获此中间值意味着避免再次进行一个或多个方法调用.

4)Debugging- 如你的问题所示,像这样分割复杂的行简化了调试.通过缩小异常的可能来源.