Java中的异常分为两种,Checked Exceptions
以及Unchecked Exceptions
。Error
、RuntimeException
及其子类都是Unchecked Exceptions
,其余所有Throwable
及其子类都是Checked Exceptions
,即需要被显式地声明或处理。
Each method in the Java Virtual Machine may be associated with zero or more exception handlers. An exception handler specifies the range of offsets into the Java Virtual Machine code implementing the method for which the exception handler is active, describes the type of exception that the exception handler is able to handle, and specifies the location of the code that is to handle that exception. An exception matches an exception handler if the offset of the instruction that caused the exception is in the range of offsets of the exception handler and the exception type is the same class as or a subclass of the class of exception that the exception handler handles. When an exception is thrown, the Java Virtual Machine searches for a matching exception handler in the current method. If a matching exception handler is found, the system branches to the exception handling code specified by the matched handler.
From jvms-2.10
如上文的JVM规范所述,每个Java方法都可能关联了一个异常处理表,其表项指出了字节码中某个范围内的代码抛出指定类型异常或其子类时,虚拟机会跳转到指定的代码行继续执行。
若当前方法没有对应的handler
,则会立即终止当前栈帧的执行并销毁之,恢复函数调用者的栈帧,并重新抛出该异常,接着到其异常表里面去找handler
。
可以使用javap -c
来查看异常处理表:
import java.io.File;
import java.io.IOException;
public class ExceptionDemo {
void foo() {
try {
File file = new File("");
file.getCanonicalPath();
} catch (IOException e) {
System.out.println("IO");
} catch (SecurityException e) {
System.out.println("Sec");
} finally {
System.out.println("Finally");
}
}
}
很显然会有一个异常处理表,并有三个表项:处理IOException
的分支,处理SecurityException
的分支,以及处理任何异常的分支finnaly
。但是还有另外两个,为了保证finally
一定能够执行,当在异常处理函数中抛出异常时也要跳到finally
的代码块中。故异常处理表中一共有5个表项:
public class ExceptionDemo {
public ExceptionDemo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
void foo();
Code:
0: new #2 // class java/io/File
3: dup
4: ldc #3 // String
6: invokespecial #4 // Method java/io/File."<init>":(Ljava/lang/String;)V
9: astore_1
10: aload_1
11: invokevirtual #5 // Method java/io/File.getCanonicalPath:()Ljava/lang/String;
14: pop
15: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
18: ldc #7 // String Finally
20: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
23: goto 77
26: astore_1
27: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
30: ldc #10 // String IO
32: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
35: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
38: ldc #7 // String Finally
40: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
43: goto 77
46: astore_1
47: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
50: ldc #12 // String Sec
52: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
55: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
58: ldc #7 // String Finally
60: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
63: goto 77
66: astore_2
67: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
70: ldc #7 // String Finally
72: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
75: aload_2
76: athrow
77: return
Exception table:
from to target type
0 15 26 Class java/io/IOException
0 15 46 Class java/lang/SecurityException
0 15 66 any
26 35 66 any
46 55 66 any
}
(完)
References: