finally代码块
当前版本的java编译器是复制 finally 代码块的内容,分别放在 try-catch 代码块所有正常执行路径以及异常执行路径的出口中。
举例
public class ExceptionFinally {
private int tryBlock;
private int catchBlock;
private int finallyBlock;
private int methodExit;
public void test() {
try {
tryBlock = 0;
} catch (Exception e) {
catchBlock = 1;
} finally {
finallyBlock = 2;
}
methodExit = 3;
}
}
查看他的字节码信息
public void test();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1
0: aload_0
1: iconst_0
2: putfield #2 // Field tryBlock:I
5: aload_0
6: iconst_2
7: putfield #3 // Field finallyBlock:I
10: goto 35
13: astore_1
14: aload_0
15: iconst_1
16: putfield #5 // Field catchBlock:I
19: aload_0
20: iconst_2
21: putfield #3 // Field finallyBlock:I
24: goto 35
27: astore_2
28: aload_0
29: iconst_2
30: putfield #3 // Field finallyBlock:I
33: aload_2
34: athrow
35: aload_0
36: iconst_3
37: putfield #6 // Field methodExit:I
40: return
每个代码块后面都跟了finally代码块,这样就确保finally代码块一定会执行。
异常屏蔽
举例:
public class ExceptionFinally {
public static void main(String[] args) {
testExceptionShield();
}
private static void testExceptionShield() {
try {
String s = null;
System.out.println(s.charAt(1));
} catch (Exception e) {
int[] a = {1, 2};
System.out.println(a[2]);
} finally {
System.out.println("finally");
}
}
}
输出
当catch代码块中出现异常时,会屏蔽掉try代码块中的异常。这是为什么呢?
从上面的字节码信息中可以看出,java只会在最后的时候将栈顶的异常抛出,而每个代码块都会将异常放到栈顶,所以前面捕获的异常就不会被抛出了。
解决办法:
Java7引入了Suppressed异常机制来解决这个问题,其核心就是允许开发者将一个异常附于另一个异常之上,这样抛出的异常就可以附带多个异常的信息。
一般catch代码块中抛出异常就好了,不建议在里面做更多的操作。
try-with-resource
JDK7 之后,Java 新增的 try-with-resource 语法糖来打开资源,并且可以在语句执行完毕后确保每个资源都被自动关闭 。
JDK7 之前所有被打开的系统资源,比如流、文件或者 Socket 连接等,都需要被开发者手动关闭,否则将会造成资源泄露。
格式:
try (resource declaration) {
// 使用的资源
} catch (ExceptionType e1) {
// 异常块
}
举例:
public class TestCode {
public static void main(String[] args) {
String line;
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
while ((line = br.readLine()) != null) {
System.out.println("Line =>" + line);
}
} catch (IOException e) {
System.out.println("IOException in try block =>" + e.getMessage());
}
}
}
通过它生成的class文件,我们发现它自动关闭了资源。
public class TestCode {
public TestCode() {
}
public static void main(String[] args) {
try {
BufferedReader br = new BufferedReader(new FileReader("test.txt"));
Throwable var3 = null;
try {
String line;
try {
while((line = br.readLine()) != null) {
System.out.println("Line =>" + line);
}
} catch (Throwable var13) {
var3 = var13;
throw var13;
}
} finally {
if (br != null) {
if (var3 != null) {
try {
br.close();
} catch (Throwable var12) {
var3.addSuppressed(var12);
}
} else {
br.close();
}
}
}
} catch (IOException var15) {
System.out.println("IOException in try block =>" + var15.getMessage());
}
}
}