目录
1、场景
在Java中,所有被打开的系统资源(流、文件、Socket连接、数据库连接等),在资源使用完毕之后,都需要开发者手动关闭,避免出现资源泄露。通常我们会用try-catch-finally方式关闭资源:
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(new File("xxx.txt"));
fos = new FileOutputStream(new File("aaa.txt"));
// 执行业务逻辑
} catch (FileNotFoundException e) {
// 异常处理
} finally {
// 关闭流
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
从以上代码可以看出,try-catch-finally方式是将资源关闭的代码写到了finally中,但是随着需要关闭的资源越来越多,finally中的关闭资源代码也会异常难看。
为了解决以上问题,我们可以使用Java7新增的try-with-resource语法糖来打开资源,可省略资源关闭的代码。
2、try-with-resource
try-with-resource语句声明了一种或多种资源,并且保证每个声明了的资源在语句结束时都会被自动关闭。那么如何定义资源,任何实现了java.lang.AutoCloseable接口的对象,都可以在try-with-resource语句中使用。
try (FileInputStream fis = new FileInputStream("xxx.txt");
FileOutputStream fos = new FileOutputStream("aaa.txt")) {
// 业务逻辑
} catch (IOException e) {
// 异常处理
}
Java7中的try-with-resource要求将所有被管理的变量都定义在资源说明头(即try后面的括号列表)中,由于某些原因,Java团队认为有时会显得过于笨拙。
所以在Java9中,增加了再try之前定义这些变量的能力,只要它们被显示地声明为最终变量,或者是实际上的最终变量即可。如下所示:
FileInputStream fis = new FileInputStream("xxx.txt");
FileOutputStream fos = new FileOutputStream("aaa.txt")
try (fis; fos) {
// 业务逻辑
} catch (IOException e) {
e.printStackTrace();
}
注意:try-with-resources语句也可以像普通的try语句一样,有catch和finally代码块。在try-with-resources语句中,任何的catch和finally代码块都在所有被声明的资源被关闭后执行。
3、异常屏蔽
try (FileInputStream fis = new FileInputStream("xxx.txt")) {
// 业务逻辑
}
如果在进行外部资源处理(try块中)时中出现了异常,并在在关闭外部资源时也出现了异常。那么此时,"关闭异常"将被抑制,"处理异常"将被抛出。
针对以上情况,可能会导致一些bug变得难以发现。所以从jdk7开始,Throwable类新增了addSuppressed方法,支持将一个异常附加到另一个异常身上,从而避免异常屏蔽。从另一个角度来说,"关闭异常"并没有丢失,而是放到了"处理异常"的异常列表中,可以通过Throwable.getSuppressed找回被抑制的异常。
以上内容为个人学习理解,如有问题,欢迎在评论区指出。
部分内容截取自网络,如有侵权,联系作者删除。