异常机制
JVM如何处理异常?
exception table
概念
方法的异常表
from :可能发生异常的起始点
to :可能发生异常的结束点
target :上述from和to之前发生异常后的异常处理者的位置
type :异常处理者处理的异常的类信息
什么时候被使用?
异常发生的时候
如何被使用?
1.JVM会在当前出现异常的方法中,查找异常表,是否有合适的处理者来处理
2.如果当前方法异常表不为空,并且异常符合处理者的from和to节点,并且type也匹配,则JVM调用位于target的调用者来处理。
3.如果上一条未找到合理的处理者,则继续查找异常表中的剩余条目
4.如果当前方法的异常表无法处理,则向上查找(弹栈处理)刚刚调用该方法的调用处,并重复上面的操作。
5.如果所有的栈帧被弹出,仍然没有处理,则抛给当前的Thread,Thread则会终止。
6.如果当前Thread为最后一个非守护线程,且未处理异常,则会导致JVM终止运行。
try...catch示例
public static void simpleTryCatch() {
try {
testNPE();
} catch (Exception e) {
e.getMessage();
}
}
字节码:
public static void simpleTryCatch();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=0
0: invokestatic #3 // Method testNPE:()V
3: goto 12
6: astore_0
7: aload_0
8: invokevirtual #5 // Method java/lang/Exception.getMessage:()Ljava/lang/String;
11: pop
12: return
Exception table:
from to target type
0 3 6 Class java/lang/Exception
try...catch...finally示例
public static void simpleTryCatch() {
try {
testNPE();
} catch (Exception e) {
e.getMessage();
}finally {
System.out.println("finally");
}
}
字节码:
public static void simpleTryCatch();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=0
0: invokestatic #3 // Method testNPE:()V
3: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
6: ldc #5 // String finally
8: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
11: goto 42
14: astore_0
15: aload_0
16: invokevirtual #8 // Method java/lang/Exception.getMessage:()Ljava/lang/String;
19: pop
20: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
23: ldc #5 // String finally
25: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
28: goto 42
31: astore_1
32: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
35: ldc #5 // String finally
37: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: aload_1
41: athrow
42: return
Exception table:
from to target type
0 3 14 Class java/lang/Exception
0 3 31 any
14 20 31 any
异常表中,有三条数据,而我们仅仅捕获了一个Exception, 异常表的后两个item的type为any; 上面的三条异常表item的意思为:
如果0到3之间,发生了Exception类型的异常,调用14位置的异常处理者。
如果0到3之间,无论发生什么异常,都调用31位置的处理者
如果14到20之间(即catch部分),不论发生什么异常,都调用31位置的处理者。
finally为什么总是被执行?
finally逻辑 被提取到 try、catch位置
public static void simpleTryCatch() {
try {
testNPE();
} catch (Exception e) {
e.getMessage();
}finally {
System.out.println("finally");
}
}
public static void simpleTryCatch();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=0
0: invokestatic #3 // Method testNPE:()V
3: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
6: ldc #5 // String finally
8: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
11: goto 42 // try提取finally逻辑,如果无异常,goto 42,执行结束
14: astore_0
15: aload_0
16: invokevirtual #8 // Method java/lang/Exception.getMessage:()Ljava/lang/String;
19: pop
20: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
23: ldc #5 // String finally
25: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
28: goto 42 // catch提取finally逻辑,如果无异常,goto 42,执行结束
31: astore_1
32: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
35: ldc #5 // String finally
37: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: aload_1
41: athrow // 如果发生异常,未被处理,执行完finally逻辑,将异常抛给调用方
42: return
Exception table:
from to target type
0 3 14 Class java/lang/Exception
0 3 31 any
14 20 31 any
return和finally的问题
在try、catch中使用return
finally都会正常被执行
public static String simpleTryCatch() {
try {
testNPE();
return "ok";
} catch (Exception e) {
e.getMessage();
return "catch";
}finally {
System.out.println("finally");
}
}
字节码:
public static java.lang.String simpleTryCatch();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=0
0: invokestatic #5 // Method testNPE:()V
3: ldc #6 // String ok
5: astore_0
6: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
9: ldc #7 // String finally try块的finally逻辑
11: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
14: aload_0
15: areturn
16: astore_0
17: aload_0
18: invokevirtual #9 // Method java/lang/Exception.getMessage:()Ljava/lang/String;
21: pop
22: ldc #10 // String catch
24: astore_1
25: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
28: ldc #7 // String finally catch块的finally逻辑
30: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
33: aload_1
34: areturn
35: astore_2
36: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
39: ldc #7 // String finally
41: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
44: aload_2
45: athrow
Exception table:
from to target type
0 6 16 Class java/lang/Exception
0 6 35 any
16 25 35 any
在finally中使用return(禁止)
finally中使用return,finally逻辑执行完,执行执行return;
public static String simpleTryCatch() {
try {
testNPE();
return "ok";
} catch (Exception e) {
e.getMessage();
return "catch";
}finally {
System.out.println("finally");
return "finally";
}
}
字节码:
public static java.lang.String simpleTryCatch();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=0
0: invokestatic #5 // Method testNPE:()V
3: ldc #6 // String ok
5: astore_0
6: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
9: ldc #7 // String finally
11: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
14: ldc #7 // String finally 执行完finally逻辑,执行return
16: areturn
17: astore_0
18: aload_0
19: invokevirtual #9 // Method java/lang/Exception.getMessage:()Ljava/lang/String;
22: pop
23: ldc #10 // String catch
25: astore_1
26: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
29: ldc #7 // String finally
31: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
34: ldc #7 // String finally 执行完finally逻辑,执行return
36: areturn
37: astore_2
38: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
41: ldc #7 // String finally
43: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
46: ldc #7 // String finally 执行完finally逻辑,执行return
48: areturn
Exception table:
from to target type
0 6 17 Class java/lang/Exception
0 6 37 any
17 26 37 any
浙公网安备 33010602011771号