是否有关于Java堆栈跟踪行号的明确文档?
在打印堆栈跟踪(它背后的逻辑,而不是实现)时,它们如何"计算"?
为了告诉你为什么我感到困惑,请使用以下代码片段:
public static void main(String[] args) {
String evilString = null;
System.out.println(new StringBuilder()
.append(evilString.toLowerCase()));
evilString.toUpperCase();
}
Run Code Online (Sandbox Code Playgroud)
它提供了:线程"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();
}
Run Code Online (Sandbox Code Playgroud)
给出:异常在线程"主"显示java.lang.NullPointerException在be.company.training.ocjp6.App.main(App.java:30)
所以我理解运行StringBuilder
方法链使它被视为1行(StringBuilder代码从我的编辑器中的第28行开始).但是如果在evilString.toUpperCase()片段中发生错误,我们就会回到第30行.
我想知道,当我看到一个堆栈跟踪时,我可以确定错误发生在哪一行(链接方法(在多行上)在我正在查看的代码中非常常见).
Rob*_*b H 11
似乎这是依赖于编译器的@kdgregory所指出的.
这是我的java -version:
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)
Run Code Online (Sandbox Code Playgroud)
使用此代码,我在堆栈跟踪的第9行NPE(与源中的物理行号匹配)
public static void main(String[] args) {
String evilString = null;
System.out.println(new StringBuilder()
.append(
evilString.toLowerCase())); // <--- NPE here (line 9)
}
Run Code Online (Sandbox Code Playgroud)
所以我用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
Run Code Online (Sandbox Code Playgroud)
源线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
Run Code Online (Sandbox Code Playgroud)
我的猜测:当在偏移量为13的invokevirtual处遇到异常时,jvm会在行号表中查找最接近的先前条目并将其放入堆栈跟踪中.