Похоже, это зависит от компилятора, как отмечено @kdgregory.
Вот моя версия Java:
java version "1.6.0_29"
Java(TM) SE Runtime Environment (build 1.6.0_29-b11-402-10M3527)
Java HotSpot(TM) Client VM (build 20.4-b02-402, mixed mode)
С этим кодом я выполняю NPE в строке 9 для трассировки стека (которая соответствует физическому номеру строки в источнике)
public static void main(String[] args) {
String evilString = null;
System.out.println(new StringBuilder()
.append(
evilString.toLowerCase())); // <--- NPE here (line 9)
}
Так что я копнул немного глубже, используя javap:
Это таблица номеров строк для main, как показано в javap -l
(таблица номеров строк показывает исходную строку: смещение инструкции
public static void main(java.lang.String[]);
LineNumberTable:
line 6: 0
line 7: 2
line 9: 12
line 8: 16
line 7: 19
line 10: 22
исходная строка 9 начинается со смещения 12.
javap -c для разборки показывает это:
public static void main(java.lang.String[]);
Code:
0: aconst_null
1: astore_1
2: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
5: new #22; //class java/lang/StringBuilder
8: dup
9: invokespecial #24; //Method java/lang/StringBuilder."<init>":()V
12: aload_1 <--- closest line in the line number table
13: invokevirtual #25; //Method java/lang/String.toLowerCase:()Ljava/lang/String; <--- NPE here
16: invokevirtual #31; //Method java/lang/StringBuilder.append: (Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #35; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
22: return
мое предположение:
когда исключение выполняется в invokevirtual со смещением 13, jvm ищет ближайшую предыдущую запись в таблице номеров строк и помещает ее в трассировку стека.