Java中的异常分为两种,Checked Exceptions以及Unchecked ExceptionsErrorRuntimeException及其子类都是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: