看《Effective Java》第三版的時候,看到了其中建議將try-finally
替換爲try-with-resources
。這個語法糖還算有意思,特此成文。java
Java庫中有不少資源須要手動關閉,好比InputStream、OutputStream、java.sql.Connection等等。在此以前,一般是使用try-finally
的方式關閉資源;Java7以後,推出了try-with-resources
聲明來替代以前的方式。 try-with-resources
聲明要求其中定義的變量實現 AutoCloseable 接口,這樣系統能夠自動調用它們的close方法,從而替代了finally中關閉資源的功能。sql
舉個栗子,下面是一個複製文件的方法,按照本來try-catch-finally
的寫法:spa
// 一個簡單的複製文件方法。
public static void copy(String src, String dst) {
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(src);
out = new FileOutputStream(dst);
byte[] buff = new byte[1024];
int n;
while ((n = in.read(buff)) >= 0) {
out.write(buff, 0, n);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
複製代碼
能夠看出,這種實現很是的醜陋。code
下面來看使用了try-with-resources
後的效果:接口
public static void copy(String src, String dst) {
try (InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst)) {
byte[] buff = new byte[1024];
int n;
while ((n = in.read(buff)) >= 0) {
out.write(buff, 0, n);
}
} catch (IOException e) {
e.printStackTrace();
}
}
複製代碼
try-with-resources
將會自動關閉try()
中的資源,而且將先關閉後聲明的資源。資源
若是不catch IOException就更加清爽了:it
public static void copy(String src, String dst) throws IOException {
try (InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst)) {
byte[] buff = new byte[1024];
int n;
while ((n = in.read(buff)) >= 0) {
out.write(buff, 0, n);
}
}
}
複製代碼
那麼try-with-resources
有什麼神奇之處呢?到底作了什麼呢?io
咱們先來看下AutoCloseable
接口:編譯
public interface AutoCloseable {
void close() throws Exception;
}
複製代碼
其中僅有一個close方法,實現AutoCloseable接口的類將在close方法中實現其關閉資源的功能。class
而try-with-resources
實際上是個語法糖,它將在編譯時編譯成關閉資源的代碼。咱們將上述例子中的代碼編譯成class文件,再反編譯回java文件,就能看到以下代碼:
public static void copy(String var0, String var1) throws IOException {
FileInputStream var2 = new FileInputStream(var0);
Throwable var3 = null;
try {
FileOutputStream var4 = new FileOutputStream(var1);
Throwable var5 = null;
try {
byte[] var6 = new byte[1024];
int var7;
while((var7 = var2.read(var6)) >= 0) {
var4.write(var6, 0, var7);
}
} catch (Throwable var29) {
var5 = var29;
throw var29;
} finally {
if (var4 != null) {
if (var5 != null) {
try {
// 關閉FileOutputStream
var4.close();
} catch (Throwable var28) {
var5.addSuppressed(var28);
}
} else {
var4.close();
}
}
}
} catch (Throwable var31) {
var3 = var31;
throw var31;
} finally {
if (var2 != null) {
if (var3 != null) {
try {
// 關閉FileInputStream
var2.close();
} catch (Throwable var27) {
var3.addSuppressed(var27);
}
} else {
var2.close();
}
}
}
}
複製代碼
除卻處理異常相關的代碼,其實就是調用了資源的close方法。
不過不得不說這個語法糖挺甜,真香。