說(shuō)到j(luò)ava.io.Closeable接口就避不開java.lang.AutoCloseable接口,因?yàn)樵趈ava版本7.0時(shí)引入了java.lang.AutoCloseable接口,同時(shí)java.io.Closeable接口便繼承自java.lang.AutoCloseable接口了。
java.io.Closeable
先說(shuō)一下Closeable接口,這個(gè)接口從java 5.0版本開始引入,其中中僅聲明了一個(gè)方法close,用于關(guān)閉一個(gè)資源。一直一來(lái)我都很困惑,就算不實(shí)現(xiàn)這個(gè)接口,我給我的類實(shí)現(xiàn)一個(gè)close方法(或者別的方法)來(lái)完成“關(guān)閉”的功能不也是一樣的么。直到我看到下面的兩段代碼。
//第一段代碼
static void copy(String src, String dest)throws IOException {
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(src);
out = new FileOutputStream(dest);
byte[] buf = new byte[1024];
int n;
while ((n = in.read(buf)) >= 0) {
out.write(buf, 0, n);
}
} finally {
if (in != null) in.close();
if (out != null) out.close();
}
}
上面這段代碼的問(wèn)題在于,finally語(yǔ)句中的close方法也可能會(huì)拋出IOException異常。如果這正好發(fā)現(xiàn)在in.close被調(diào)用之時(shí),那么這個(gè)異常就會(huì)阻止out.close被調(diào)用,從而使輸出流保持在打開狀態(tài)。所以這個(gè)程序使得finally可能被意外結(jié)束。解決方式是將每一個(gè)close都包裝在一個(gè)try語(yǔ)句塊中。從java 5.0版本開始,可以利用Closeable接口。
//第二段代碼
// 對(duì)第一段代碼中的finally語(yǔ)句改造如下
finally {
closeIgnoringIOException(in);
closeIgnoringIOException(out);
}
private static void closeIgnoringIOException(Closeable c) {
if (c != null) {
try {
c.close();
} catch (IOException ex) { }
}
}
基于以上兩段代碼我知道了java.io.Closeable接口的用處。
java.lang.AutoCloseable
在java 7.0j時(shí)引入了java.lang.AutoCloseable,并且java.io.Closeable接口繼承自 java.lang.AutoCloseable。很多資源類都直接或間接的實(shí)現(xiàn)了此接口。其實(shí)這個(gè)接口與try-with-resources語(yǔ)法是密切相關(guān)的。
從AutoCloseable的注釋可知它的出現(xiàn)是為了更好的管理資源,準(zhǔn)確說(shuō)是資源的釋放,當(dāng)一個(gè)資源類實(shí)現(xiàn)了該接口close方法,在使用try-with-resources語(yǔ)法創(chuàng)建的資源拋出異常后,JVM會(huì)自動(dòng)調(diào)用close 方法進(jìn)行資源釋放,當(dāng)沒(méi)有拋出異常正常退出try-block時(shí)候也會(huì)調(diào)用close方法。
//第三段代碼
static void copy(String src, String dest)throws IOException {
try (InputStream in=new FileInputStream(src);OutputStream out=new FileOutputStream(dest)){
byte[] buf = new byte[1024];
int n;
while ((n = in.read(buf)) >= 0) {
out.write(buf, 0, n);
}
}catch(Exception e) {
System.out.println("catch block:"+e.getLocalizedMessage());
}finally{
System.out.println("finally block");
}
}
因?yàn)镮nputStream和OutputStream都實(shí)現(xiàn)了java.io.Closeable接口(間接實(shí)現(xiàn)了java.lang.AutoCloseable接口)所以上面的【第三段代碼】與【第二段代碼的】一樣“安全”。
try-with-resources
try-with-resources 是在java 7.0 版本時(shí)引入的新語(yǔ)法特性。使用它配合java.lang.AutoCloseable接口可以更好的對(duì)資源進(jìn)行釋放,減少繁瑣的異常處理。
- 使用try-with-resources結(jié)構(gòu)無(wú)論是否拋出異常在try-block執(zhí)行完畢后都會(huì)調(diào)用資源的close方法;
- 使用try-with-resources結(jié)構(gòu)創(chuàng)建多個(gè)資源,try-block執(zhí)行完畢后調(diào)用的close方法的順序與創(chuàng)建資源順序相反;
- 使用try-with-resources結(jié)構(gòu),try-block塊拋出異常后先執(zhí)行所有資源(try的()中聲明的)的close方法然后在執(zhí)行catch里面的代碼然后才是finally;
- 只用在try的()中聲明的資源的close方法才會(huì)被調(diào)用,并且當(dāng)對(duì)象銷毀的時(shí)候close不會(huì)被再次調(diào)用;
- 使用try-with-resources結(jié)構(gòu)無(wú)須顯式調(diào)用資源釋放,編程效率高,代碼更簡(jiǎn)潔。