java中所有异常都是Throwable 类或者其子类的实例,Throwable类有两个直接子类Error、Exception。Error为应用程序无法捕获的异常,发生Error时需要中止线程。Exception与Error不同,发生时可捕获异常进行处理。
处理异常包括使用try,catch,finally关键字进行处理
try:标记需要捕获异常的代码。
catch:指定捕获某种异常进行处理。
finally:在try、catch之后使用,使用finally的代码段总是执行,可以避免某些关键代码不被执行。
对于异常捕获用法如下
public void testTryCatch() {
try {
System.out.println("try");
} catch (NullPointerException | ArrayIndexOutOfBoundsException e) {
System.out.println("catch");
} finally {
System.out.println("finally");
}
}
说完异常使用方式,简单说下jvm如何处理异常,首先将上述代码对应类编译为class文件,然后使用javap解析class文件如下
public void testTryCatch();
Code:
0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #21 // String try
5: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: goto 42
11: astore_1
12: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
15: ldc #29 // String catch
17: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
23: ldc #31 // String finally
25: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
28: goto 50
31: astore_2
32: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
35: ldc #31 // String finally
37: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
40: aload_2
41: athrow
42: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
45: ldc #31 // String finally
47: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
50: return
Exception table:
from to target type
0 8 11 Class java/lang/NullPointerException
0 8 11 Class java/lang/ArrayIndexOutOfBoundsException
0 20 31 any
通过解析后字节码可以看到 Exception table,该table为异常表,其中from为开始指针,to为结束指针,target为异常处理起始指针,type为异常处理类型。当程序发生异常时,java虚拟机会遍历该表,当触发的异常与表中定义异常匹配则执行target对应指针的字节码。
在jdk1.8中finally处理方法是将finally内字节码添加到每个执行代码块中并且监控整个代码块在其最后增加finally进行处理。