此心光明这橙,亦復(fù)何言
Try-with-resources
Try-with-resources是Java7出現(xiàn)的一個新的異常處理機制导披,它能夠很容易地關(guān)閉在try-catch語句塊中使用的資源撩匕。
傳統(tǒng)的關(guān)閉資源方式是利用Try-Catch-Finally管理資源(舊的代碼風(fēng)格) 即在Java7以前程序中使用的資源需要被明確地關(guān)閉。
private static void printFile() throws IOException {
InputStream input = null;
try{
input = new FileInputStream("d:\\hello.txt");
int data = input.read();
while(data != -1){
System.out.print((char) data);
data = input.read();
}
} finally {
if(input != null){
input.close();
}
}
}
以上程序 try語句塊中有3處能拋出異常,finally語句塊中有一處會拋出異常漠趁。
不論try語句塊中是否有異常拋出忍疾,finally語句塊始終會被執(zhí)行。這意味著甥绿,不論try語句塊中發(fā)生什么脚囊,InputStream 都會被關(guān)閉谭确,或者說都會試圖被關(guān)閉图谷。如果關(guān)閉失敗阱洪,close()方法也可能會拋出異常。
假設(shè)try語句塊拋出一個異常澄峰,然后finally語句塊被執(zhí)行。同樣假設(shè)finally語句塊也拋出了一個異常绸硕。那么哪個異常會根據(jù)調(diào)用棧往外傳播魂毁?
即使try語句塊中拋出的異常與異常傳播更相關(guān),最終還是finally語句塊中拋出的異常會根據(jù)調(diào)用棧向外傳播咬崔。
在Java7以后烦秩,對于上面的例子可以用try-with-resource 結(jié)構(gòu)這樣寫:
private static void printFileJava7() throws IOException {
try(FileInputStream input = new FileInputStream("d:\\hello.txt")) {
int data = input.read();
while(data != -1){
System.out.print((char) data);
data = input.read();
}
}
}
注意方法中的第一行:
try(FileInputStream input = new FileInputStream("d:\\hello.txt"))
這就是try-with-resource 結(jié)構(gòu)的用法。FileInputStream 類型變量就在try關(guān)鍵字后面的括號中聲明兜蠕。而且一個FileInputStream 類型被實例化并被賦給了這個變量抛寝。
當(dāng)try語句塊運行結(jié)束時曙旭,F(xiàn)ileInputStream 會被自動關(guān)閉晶府。這是因為FileInputStream 實現(xiàn)了java中的java.lang.AutoCloseable接口。所有實現(xiàn)了這個接口的類都可以在try-with-resources結(jié)構(gòu)中使用剂习。
當(dāng)try-with-resources結(jié)構(gòu)中拋出一個異常书劝,同時FileInputStream被關(guān)閉時(調(diào)用了其close方法)也拋出一個異常,try-with-resources結(jié)構(gòu)中拋出的異常會向外傳播购对,而FileInputStream被關(guān)閉時拋出的異常被抑制了。這與文章開始處利用舊風(fēng)格代碼的例子(在finally語句塊中關(guān)閉資源)相反垂蜗。
使用多個資源
你也可以在塊中使用多個資源而且這些資源都能被自動地關(guān)閉解幽。下面是例子:
private static void printFileJava7() throws IOException {
try(FileInputStream input = new FileInputStream("d:\\hello.txt"); BufferedInputStream bufferedInput = new BufferedInputStream(input))
{
int data = buffereInput.read();
while(data != -1){
System.out.println( (char) data);
data = bufferedInput.read();
}
}
}
上面的例子在try關(guān)鍵字后的括號里創(chuàng)建了兩個資源——FileInputStream 和BufferedInputStream。當(dāng)程序運行離開try語句塊時片部,這兩個資源都會被自動關(guān)閉霜定。
這些資源將按照他們被創(chuàng)建順序的逆序來關(guān)閉。首先BufferedInputStream 會被關(guān)閉辖所,然后FileInputStream會被關(guān)閉磨德。
自定義AutoCloseable 實現(xiàn)
這個try-with-resources結(jié)構(gòu)里不僅能夠操作java內(nèi)置的類。你也可以在自己的類中實現(xiàn)java.lang.AutoCloseable接口典挑,然后在try-with-resources結(jié)構(gòu)里使用這個類。
AutoClosable 接口僅僅有一個方法拙寡,接口定義如下:
public interface AutoClosable{
public void close() throws Exception;
}
任何實現(xiàn)了這個接口的方法都可以在try-with-resources結(jié)構(gòu)中使用顾犹。下面是一個簡單的例子:
public class MyAutoClosable implements AutoClosable{
public void doIt(){
System.out.println("MyAutoClosable doing it!");
}
@Override
public void close() throws Exception{
System.out.println("MyAutoCloseable Closed!");
}
}
下面是MyAutoClosable 在try-with-resources結(jié)構(gòu)中使用的例子:
private static void myAutoClosable() throws Exception{
try(MyAutoClosable myAutoClosable = new MyAutoClosable()){
myAutoClosable.doIt();
}
}
當(dāng)方法myAutoClosable.doIt()被調(diào)用時炫刷,下面是打印到System.out的輸出:
MyAutoClosable doing it!
MyAutoClosable closed!
通過上面這些你可以看到,不論try-catch中使用的資源是自己創(chuàng)造的還是java內(nèi)置的類型浑玛,try-with-resources都是一個能夠確保資源能被正確地關(guān)閉的強大方法。
小結(jié):
自動關(guān)閉資源的try語句相當(dāng)于包含了隱式的finally塊(用于關(guān)閉資源)极阅,因此這個try語句可以既沒有catch塊涨享,也沒有finally塊。
-
被自動關(guān)閉的資源必須實現(xiàn)Closeable或AutoCloseable接口奔脐。(Closeable是AutoCloseable的子接口吁讨,Closeeable接口里的close()方法聲明拋出了IOException,;AutoCloseable接口里的close()方法聲明拋出了Exception)
- Java7幾乎把所有的“資源類”(包括文件IO的各種類,JDBC編程的Connection建丧、Statement等接口……)進行了改寫,改寫后的資源類都實現(xiàn)了AutoCloseable或Closeable接口
-
Java7新增的自動關(guān)閉資源的try語句允許在try關(guān)鍵字后緊跟一對圓括號橄维,里面可以聲明闭翩、初始化一個或多個資源,此處的資源指的是那些必須在程序結(jié)束時顯示關(guān)閉的資源(數(shù)據(jù)庫連接兑障、網(wǎng)絡(luò)連接等)蕉汪,try語句會在該語句結(jié)束時自動關(guān)閉這些資源。
- 被關(guān)閉的資源必須放在try語句后的圓括號中聲明者疤、初始化。如果程序有需要自動關(guān)閉資源的try語句后可以帶多個catch塊和一個finally塊革砸。