Java 7新特性:自動化資源管理
51CTO曾在《Java 7:最新特性更新、代碼示例及性能測試》中為大家介紹過Project Coin的項目。Project Coin的一個突出特點就是具備了自動化資源管理(即ARM)能力,這個能力是Java 7特有的,目前使用Java 6的朋友在編譯時很多庫都需要重新編譯以適應Java 6的需要。其目的在于當遇到錯誤或是成功執(zhí)行完代碼塊后能夠輕松處理好外部資源。其最初實現(xiàn)位于Open JDK中??紤]如下繁瑣的文件拷貝操作,代碼來自于Java Bytestream教程:
- FileInputStream in = null;
- FileOutputStream out = null;
- try {
- in = new FileInputStream("xanadu.txt");
- out = new FileOutputStream("outagain.txt");
- int c;
- while ((c = in.read()) != -1)
- out.write(c);
- } finally {
- if (in != null)
- in.close();
- if (out != null)
- out.close();
- }
上面不僅有大量的樣版代碼,而且InputStream.close()的文檔表明它會拋出IOException(OutputStream也存在類似的異常,無論何種情況,要想成功編譯這些代碼,要么在外面加上catch塊,要么將異常繼續(xù)往外拋)。
try-catch-finally塊的語義范圍還要求變量FileInputStream in與FileOutputStream out聲明在塊的外面(如果定義在try塊內,那么catch塊與finally塊就訪問不到了)。
為了減少上面這些樣版代碼并且收緊塊中所用的資源范圍,Java語言在try塊中新增了一些內容。最初的try-with-resources塊(或者叫做ARM塊)規(guī)范已經(jīng)擁有實現(xiàn)了,隨后該規(guī)范被納入到JDK 7 build 105中。
新的接口java.lang.AutoCloseable被加到了提案API中,它只定義了一個會拋出Exception的方法close()。該接口是java.io.Closeable的父接口,這意味著所有的InputStream與OutputStream都會自動享受到該行為所帶來的好處。此外,F(xiàn)ileLock與ImageInputStream也實現(xiàn)了AutoCloseable接口。
這樣,上面的代碼就可以這樣來寫:
- try (
- FileInputStream in = new FileInputStream("xanadu.txt");
- FileOutputStream out = new FileOutputStream("outagain.txt")
- ) {
- int c;
- while((c=in.read()) != -1 )
- out.write();
- }
在try塊的末尾,無論是正常結束還是拋出了異常,out與in資源都會自動調用close()方法。此外,與之前示例不同的是out.close()與in.close()保證會執(zhí)行(在之前的示例中,一旦in.close()方法拋出了異常,隨后的out.close()方法就沒有機會執(zhí)行了)。
關于這種方式,還有一些微妙之處值得我們注意:
◆如上代碼所示,在資源部分中,最后一個資源后面是不允許使用分號的。
◆資源塊使用()分隔,而不是常見的{},以此將其與現(xiàn)有的try塊分隔開來。如果存在資源塊,那么里面必須要包含一個或多個資源定義語句。
◆每個資源定義具有如下形式:type var = expression;在資源塊中不能使用通常的語句。
◆資源都是隱式final的,也就是說即便沒有使用final,這些資源也都是final的。如果嘗試為資源變量賦值會得到一個編譯期錯誤。
◆資源必須是AutoCloseable的子類型,如果不是的話會得到一個編譯期錯誤。
◆資源關閉的順序與定義的順序正好相反。換句話說,在上面的代碼示例中,out.close()要先于in.close()得到調用。這么做可以構建嵌套的流,然后從外向內關閉流,這要比按順序關閉更好(也就是說,可以在底層的流關閉前先清空緩存)。
◆每個塊可以生成n+1個異常,n是資源的數(shù)量。這出現(xiàn)在代碼主體拋出了異常,然后每個資源關閉語句也都拋出異常的情況下。在這種情況下,代碼主體的異常將被拋出,但其他的異常將會被添加到異常的抑制列表(suppressed exception list)中??梢酝ㄟ^getSuppressedExceptions()方法訪問這些異常信息。
◆異常堆棧追蹤信息可以帶有Suppressed前綴:在這些情況下,序列化的Throwable格式也有所不同(如果Java 6客戶端調用了遠程Java 7運行時中的服務會出現(xiàn)這個問題,反之亦然)。
◆javax.swing與java.sql目前并不會加入到ARM中;類需要繼承AutoCloseable才能為ARM所用。JDBC 4.1如果能夠成為JDK 7的一部分,那么它也將支持ARM,但具體時間尚未確定。
能夠移除Java開發(fā)者每天都要編寫的樣版代碼對生產(chǎn)力的提升是個促進,雖然JDK 7具備了這種能力,但有時需要在編寫代碼前利用這種能力。很多庫都需要重新編譯以適應Java 6的需要,無論何時,只要使用了自動化資源管理,那么它就只能用于使用-target 7編譯的代碼。等到Java 6壽終正寢,并且Java 8發(fā)布后,使用ARM就會成為自然而然的事情了。
原文名稱:Automatic Resource Management in Java
原文作者:Alex Blewitt
原文地址:http://www.infoq.com/news/2010/08/arm-blocks
【編輯推薦】