有没有关于
Java堆栈跟踪行号的明确文档?
当打印堆栈跟踪(后面的逻辑,而不是实现)时,他们如何“计算”?
当打印堆栈跟踪(后面的逻辑,而不是实现)时,他们如何“计算”?
public static void main(String[] args) { String evilString = null; System.out.println(new StringBuilder() .append(evilString.toLowerCase())); evilString.toUpperCase(); }
它给:
线程中的异常“main”java.lang.NullPointerException
at.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.company.training.ocjp6.App.main(App.java:30)
所以我明白,运行StringBuilder方法的链接使它被视为1行(StringBuilder代码从我的编辑器的第28行开始).但是如果在evilString.toUpperCase()代码片段中发生错误,那么我们将以第30行为准.
解决方法
像这样,似乎是编译器依赖于@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)
有了这个代码,我的NPE在第9行每堆栈跟踪(与源中的物理行号相匹配)
public static void main(String[] args) { String evilString = null; System.out.println(new StringBuilder() .append( evilString.toLowerCase())); // <--- NPE here (line 9) }
所以我用javap挖出一点点:
这是主要的行号表,如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
我猜:当在偏移量13处的invokevirtual处遇到异常时,jvm将查找行号表中最接近的先前条目,并将其放在堆栈跟踪中.