Когда я получаю NPE, я получаю трассировку стека с номером строки. Это полезно, но если строка очень плотная и/или содержит вложенное выражение, все равно невозможно определить, какая ссылка была нулевой.
Конечно, эта информация должна быть доступна где-то. Есть ли способ понять это? (Если не 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)
Итак, это указывает на invokevirtual # 5 со смещением 17! Просто КАК ОХЛАЖДЕНИЕ ЭТО?