是否有可能追踪哪个表达式导致了 NPE?
2022-09-04 22:18:24
当我获得 NPE 时,我将获得带有行号的堆栈跟踪。这很有帮助,但是如果行非常密集和/或包含嵌套表达式,仍然无法确定哪个引用为 null。
当然,这些信息一定在某个地方可用。有没有办法解决这个问题?(如果不是java表达式,那么至少导致NPE的字节码指令也会有所帮助)
编辑#1:我看到一些评论建议打破这条线,等等,这没有冒犯,真的是非建设性和无关紧要的。如果我能做到这一点,我会有!让我们说,这种修改源代码是不可能的。
编辑#2:apangin在下面发布了一个很好的答案,我接受了。但是,我必须在这里为任何不想自己尝试的人提供输出,这很酷!;)
假设我有这个驱动程序TestNPE.java
1 public class TestNPE {
2 public static void main(String[] args) {
3 int n = 0;
4 String st = null;
5
6 System.out.println("about to throw NPE");
7 if (n >= 0 && st.isEmpty()){
8 System.out.println("empty");
9 }
10 else {
11 System.out.println("othereise");
12 }
13 }
14
15 }
字节码看起来像这样(仅显示main()方法并省略其他不相关的部分)
Code:
stack=2, locals=3, args_size=1
0: iconst_0
1: istore_1
2: aconst_null
3: astore_2
4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
7: ldc #3 // String about to throw NPE
9: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
12: iload_1
13: iflt 34
16: aload_2
17: invokevirtual #5 // Method java/lang/String.isEmpty:()Z
20: ifeq 34
23: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
26: ldc #6 // String empty
28: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
31: goto 42
34: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
37: ldc #7 // String othereise
39: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
42: return
现在,当您使用代理运行 TestNPE 驱动程序时,您将获得此
$ java -agentpath:libRichNPE.o TestNPE
about to throw NPE
Exception in thread "main" java.lang.NullPointerException: location=17
at TestNPE.main(TestNPE.java:7)
因此,这指向偏移量 17 处的调用虚拟 #5!这有多酷?