在Java编程过程中,如果打开了外部资源(文件、数据库连接、网络连接等),我们必须在资源使用完后手动关闭他们,因为外部资源不由JVM管理,无法被JVM垃圾回收器回收,外部资源没有正确关闭将会导致资源泄露,将会导致文件被异常占用,数据库连接过多导致连接池满等问题。
为了确保外部资源被正常关闭,通常关闭代码被写入finnaly代码块中,我们还必须注意到关闭资源时可能抛出的异常,如下:
public static void main(String ... args) {
tryFinally();
}
private static void tryFinally() {
FileInputStream fileInputStream = null;
try{
fileInputStream = new FileInputStream(new File("src/main/resources/test.txt"));
byte [] bytes = new byte[1024];
int length = fileInputStream.read(bytes);
System.out.println(new String(bytes, 0, length));
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
} finally {
if(fileInputStream != null) {
try {
fileInputStream.close();
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
}
JDK7中新增了try-with-resource语法,当一个外部资源对象(如:FileInputeStream对象)实现了AutoCloseable接口,那么就可以适用于try-with-resource模块中,以上代码可以简化为:
public static void main(String ... args) {
tryWithResource();
}
private static void tryWithResource() {
try(FileInputStream fileInputStream = new FileInputStream(new File("src/main/resources/test.txt"))) {
byte [] bytes = new byte[1024];
int length = fileInputStream.read(bytes);
System.out.println(new String(bytes, 0, length));
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
try-with-resource 是JDK实现的一个语法糖,分编译以上代码,try-with-resource部分代码为:
private static void tryWithResource() {
try {
FileInputStream fileInputStream = new FileInputStream(new File("src/main/resources/test.txt"));
Throwable var1 = null;
try {
byte[] bytes = new byte[1024];
int length = fileInputStream.read(bytes);
System.out.println(new String(bytes, 0, length));
} catch (Throwable var12) {
var1 = var12;
throw var12;
} finally {
if (fileInputStream != null) {
if (var1 != null) {
try {
fileInputStream.close();
} catch (Throwable var11) {
var1.addSuppressed(var11);
}
} else {
fileInputStream.close();
}
}
}
} catch (IOException var14) {
throw new RuntimeException(var14.getMessage(), var14);
}
}
代码仍然使用try-catch-finnaly的方式处理,稍有不同的是对资源关闭时产生异常的处理,反编译代码使用了异常抑制。当对资源进行处理时遇到异常,且在随后关闭资源时又遇到异常,那么catch到的将会是对资源处理时遇到的异常,资源关闭时遇到的异常将被抑制,被抑制的异常会出现在抛出的异常堆栈中,可以通过getSuppressed方法获取被抑制的异常。