1. 程式人生 > 其它 >try-with-resource 關閉資源

try-with-resource 關閉資源

技術標籤:Javajava

Try-with-resources

Try-with-resources是Java7中一個新的異常處理機制,它能夠很容易地關閉在try-catch語句塊中使用的資源。

舊的程式碼風格,傳統的try-catch-finally

private static void printFile() throws IOException {
    InputStream input = null;
    
    try {
        input = new FileInputStream("file.txt");
        int
data = input.read(); while(data != -1){ System.out.print((char) data); data = input.read(); } }catch(Exception e){ log.info(e.getMessage) } finally { if(input != null){ input.close(); } } }

不論try語句塊中是否有異常丟擲,finally語句塊始終會被執行。這意味著,不論try語句塊中發生什麼,InputStream 都會被關閉,或者說都會試圖被關閉。如果關閉失敗,InputStream close()方法也可能會丟擲異常。

假設try語句塊丟擲一個異常,然後finally語句塊被執行。同樣假設finally語句塊也丟擲了一個異常。那麼哪個異常會根據呼叫棧往外傳播?即使try語句塊中丟擲的異常與異常傳播更相關,最終還是finally語句塊中丟擲的異常會根據呼叫棧向外傳播。

用try-with-resource 結構寫

private static void printFileJava7() {
    try (
            FileInputStream input = new FileInputStream("file.txt")
    ) {

        int data =
input.read(); while (data != -1) { System.out.print((char) data); data = input.read(); } } catch (Exception e) { e.printStackTrace(); } }

try(FileInputStream input = new FileInputStream(“file.txt”)) 就是try-with-resource 結構的用法。FileInputStream 型別變數就在try關鍵字後面的括號中宣告,一個FileInputStream 型別被例項化並被賦給了這個變數。

當try語句塊執行結束時,FileInputStream 會被自動關閉。這是因為FileInputStream 實現了java中的java.lang.AutoCloseable介面。所有實現了這個介面的類都可以在try-with-resources結構中使用。

異常傳播:

當try-with-resources結構中丟擲一個異常,同時FileInputStreami被關閉時(呼叫了其close方法)也丟擲一個異常。try-with-resources結構中丟擲的異常會向外傳播,而FileInputStreami被關閉時丟擲的異常被抑制了。這與舊風格程式碼的例子(在finally語句塊中關閉資源)相反。

使用多個資源

/**
 * 上傳單個檔案
 *
 * @param file       檔案的控制代碼
 * @param outputPath 輸出的最終檔案地址
 */
public void saveFile(MultipartFile file, String outputPath) {
    try (
            FileInputStream fis = (FileInputStream) file.getInputStream();
            FileOutputStream fos = new FileOutputStream(outputPath);
            FileChannel inChannel = fis.getChannel();
            FileChannel outChannel = fos.getChannel();
    ) {
        //通道間傳輸資料
        inChannel.transferTo(0, inChannel.size(), outChannel);
    } catch (Exception e) {
        logger.info("儲存檔案失敗:{}", e.getMessage());
    }
}

當程式執行離開try語句塊時,所有資源都會被自動關閉。這些資源將按照他們被建立順序的逆序來關閉。首先outChannel會被關閉,然後inChannel、fos、fis會被關閉。

自定義 AutoCloseable 實現

這個try-with-resources結構裡不僅能夠操作java內建的類。你也可以在自己的類中實現java.lang.AutoCloseable介面,然後在try-with-resources結構裡使用這個類。

package t1;

public class MyClose1 implements AutoCloseable {

    public void doIt() {
        System.out.println("MyClose1 doing!");
    }

    @Override
    public void close() throws Exception {
        System.out.println("MyClose1 Closed!");
    }
}
package t1;

public class MyClose2 implements AutoCloseable {

    public void doIt() {
        System.out.println("MyClose2 doing!");
    }

    @Override
    public void close() throws Exception {
        System.out.println("MyClose2 Closed!");
    }
}

測試執行:

package t1;

/**
 * @author zhe.xiao
 * @date 2020-12-07
 * @description
 */
public class Test {
    public static void main(String[] args) {
        try (
                MyClose1 mc1 = new MyClose1();
                MyClose2 mc2 = new MyClose2();
        ) {
            mc1.doIt();
            mc2.doIt();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

列印:

image-20201207114337257