推薦:Java網絡程式設計彙總
使用try-with-resources優雅關閉資源
JDK1.7之後,引入了
try-with-resources
,使得關閉資源操作無需層層嵌套在
finally
中,代碼簡潔不少,本質是一個文法糖,能夠使用
try-with-resources
關閉資源的類,必須實作
AutoCloseable
接口。
JDK1.7版本之前,傳統的關閉資源操作如下:
public static void main(String[] args){
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream("file.txt");
fileInputStream.read();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
assert fileInputStream != null;
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
可以看到,為了確定資源關閉正常,需要
finally
中再嵌入
try-catch
,
try-catch
中打開資源越多,
finally
嵌套越深,可能會導緻關閉資源的代碼比業務代碼還要多。
但是使用了
try-with-resources
文法後,上面的例子可改寫為:
try(FileInputStream fileInputStream1 = new FileInputStream("file.txt")){
fileInputStream1.read();
} catch (IOException e) {
e.printStackTrace();
}
如何判讀資源是否真的被關閉了呢,我們手寫個Demo:
實作
AutoCloseable
接口的資源類。
class MyResource implements AutoCloseable{
public void open(){
System.out.println("resource is open!");
}
@Override
public void close() throws Exception {
System.out.println("resource is close!");
}
}
調用方:
public static void main(String[] args){
try(MyResource myResource = new MyResource()){
myResource.open();
} catch (Exception e) {
e.printStackTrace();
}
}
輸出如下,可以看到
close
方法被自動調用了。
resource is open!
resource is close!
底層原理是什麼呢,看一下編譯後的
class
檔案:
try {
MyResource myResource = new MyResource();
Throwable var2 = null;
try {
myResource.open();
} catch (Throwable var12) {
var2 = var12;
throw var12;
} finally {
if (myResource != null) {
if (var2 != null) {
try {
myResource.close();
} catch (Throwable var11) {
var2.addSuppressed(var11);
}
} else {
myResource.close();
}
}
}
} catch (Exception var14) {
var14.printStackTrace();
}
}
很明顯,編譯器生成了
finally
代碼塊,并在其中調用了
close
方法,同JDK1.7之前的關閉資源操作的實作原理是相同的,但是可以看到,這裡多調用了一個
addSuppressed
方法,這麼做其實是為了處理異常屏蔽,什麼是異常屏蔽,首先,我們先修改一下剛剛的Demo,使資源類在
open
和
close
方法中抛出異常,并且使用JDK1.7之前的關閉資源的方法,資源類以及調用方代碼修改如下:
public void open() throws IOException {
System.out.println("resource is open!");
throw new IOException("open() exception!");
}
@Override
public void close() throws Exception {
System.out.println("resource is close!");
throw new IOException("close() exception!");
}
public static void main(String[] args) throws Exception {
MyResource myResource = null;
try{
myResource = new MyResource();
myResource.open();
}finally {
try {
myResource.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
控制台列印如下:
open
方法抛出的異常被自動忽略了,而異常資訊丢失将導緻程式調試困難,是以
try-with-resources
文法中加入了
addSuppressed
處理異常屏蔽,現在修改Demo為使用
try-with-resource
關閉資源,調用方代碼如下:
public static void main(String[] args) throws Exception {
try(MyResource myResource = new MyResource()){
myResource.open();
}
}
控制台列印如下圖:
異常資訊中多了提示:
close
方法中抛出的異常被
open
方法中抛出的異常抑制了。