Документация по номерам строк в следах стека - PullRequest
10 голосов
/ 02 января 2012

Есть ли четкая документация по номерам строк трассировки стека Java?
Как они «рассчитываются» при печати трассировки стека (логика позади нее, а не реализация)?

Чтобы показать, почему я запутался, возьмите следующий фрагмент кода:

public static void main(String[] args) {
        String evilString = null;
        System.out.println(new StringBuilder()
                .append(evilString.toLowerCase()));
        evilString.toUpperCase();
    }

Это дает: Исключение в потоке "main" java.lang.NullPointerException на be.company.training.ocjp6.App.main (App.java:28)

Пока следующий кусок кода:

public static void main(String[] args) {
        String evilString = null;
        System.out.println(new StringBuilder()
                .append("".toLowerCase()));
        evilString.toUpperCase();
    }

Дает: Исключение в потоке "main" java.lang.NullPointerException at be.company.training.ocjp6.App.main (App.java:30)

Итак, я понимаю, что выполнение цепочки методов StringBuilder делает ее обработанной как 1 строку (код StringBuilder начинается в строке 28 в моем редакторе). Но если ошибка происходит во фрагменте evilString.toUpperCase (), мы возвращаемся к строке 30.

Я хочу знать, чтобы, когда я вижу трассировку стека, я мог точно знать, в какой строке произошла ошибка (методы цепочки (в несколько строк) очень распространены в коде, который я рассматриваю).

Ответы [ 2 ]

11 голосов
/ 03 января 2012

Похоже, это зависит от компилятора, как отмечено @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 ищет ближайшую предыдущую запись в таблице номеров строк и помещает ее в трассировку стека.

0 голосов
/ 02 января 2012

Вы уверены, что "" равно null в Java?Я считаю, что это источник вашего замешательства.Вы пытались написать "".toUpperCase(); в строке 30?

...