最近idea集成了SonarLint插件,代码检测会有以下截图问题:

传统关闭资源方式(try-finally)
为了确保外部资源一定要被关闭,通常关闭代码被写入finally代码块中:
public static void main(String[] args) {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(new File("C:\\test.txt"));
System.out.println(fileInputStream.read());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这种方式关闭资源时,要考虑到关闭IO流时可能会出现的异常问题;特别是IO对象比较多时,使用finally关闭资源,可能会出现finally嵌套,代码不简洁。
try-with-resource方式
在JDK7中新增了try-with-resource语法:当一个外部资源的句柄对象(比如FileInputStream对象)实现了AutoCloseable接口,那么就可以将上面的板式代码简化为如下形式:
public static void main(String[] args) {
try (FileInputStream fileInputStream = new FileInputStream(new File("C:\\test.txt"))) {
System.out.println(fileInputStream.read());
} catch (IOException e) {
e.printStackTrace();
}
}
对比传统关闭资源方式,此种写法代码非常简洁。
实现原理
try-with-resource并不是JVM虚拟机的新增功能,只是JDK实现了一个语法糖,
编译器会自动帮生成finally块,并且在里面调用了资源的close方法。
可以反编译class文件查看:
【注:有些反编译工具反编译后的内容和java源代码一致,比如jd-gui;idea自带的反编译插件java-decompiler则正常】:
public static void main(String[] args) {
try {
FileInputStream fileInputStream = new FileInputStream(new File("C:\\test.txt"));
Throwable var2 = null;
try {
System.out.println(fileInputStream.read());
} catch (Throwable var12) {
var2 = var12;
throw var12;
} finally {
if (fileInputStream != null) {
if (var2 != null) {
try {
fileInputStream.close();
} catch (Throwable var11) {
var2.addSuppressed(var11);
}
} else {
fileInputStream.close();
}
}
}
} catch (IOException var14) {
var14.printStackTrace();
}
}
异常屏蔽
在上述反编译代码中有一行:
var2.addSuppressed(var11);
从Java 1.7开始,Throwable类新增了addSuppressed方法:当对外部资源进行处理时【System.out.println(fileInputStream.read())】,如果遭遇了异常,且在随后的关闭外部资源过程中【fileInputStream.close()】,又遭遇了异常,那么你catch到的将会是对外部资源进行处理时遭遇的异常,关闭资源时遭遇的异常将被“抑制”但不是丢弃,通过异常的getSuppressed方法,可以提取出被屏蔽的异常。