Java 7 Try-With-Resources

JasonTam發表於2018-11-02

前言

最近在看程式碼的時候發現了IO流怎麼都不需要自己手動關閉的呢,還以為是別人忘記關。結果一問,尷尬了。這居然是Java 7 的新特性。因此,特地的記錄下來了。

image

1. try-with-resources是什麼來的?

try-with-resources,就是Java 7中的新特性之一。其本質是語法糖,在編譯時會進行轉化為 try-catch-finally 語句。編繹器自動在try-with-resources後面增加了判斷物件是否為null,如果不為null,則呼叫close()函式的的位元組碼。

而且在try-with-resources中的變數必須實現AutoCloseable介面.

try-with-resources的語法:

// try-with-resources - the the best way to close resources!
static String firstLineOfFile(String path) throws IOException {
    try (BufferedReader br = new BufferedReader(
           new FileReader(path))) {
       return br.readLine();
    }
}
複製程式碼

這麼一看起來,的確提高了可讀性。

2. 為什麼要使用try-with-resources?

至於為什麼要使用try-with-resources。可以看看try-finally使用的情況

在沒有try-with-resources之前,這種語法最能確保關閉資源,無論是丟擲異常還是返回。但是 可能會由於某些原因br.readLine()方法發生異常了,在這種情況下,close()方法呼叫也失敗了,那麼第一個異常會被第二個異常給沖掉,在異常跟蹤棧中也找不到第一個異常的資訊。這對於除錯的時候來說是非常困難的。

static String firstLineOfFile(String path) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        br.close();
    }
}
複製程式碼

但如果在多個資源的情況下呢.變得難看了,不利於閱讀了。

// try-finally is ugly when used with more than one resource!
static void copy(String src, String dst) throws IOException {
    InputStream in = new FileInputStream(src);
    try {
        OutputStream out = new FileOutputStream(dst);
        try {
            byte[] buf = new byte[BUFFER_SIZE];
            int n;
            while ((n = in.read(buf)) >= 0)
                out.write(buf, 0, n);
        } finally {
            out.close();
        }
    } finally {
        in.close();
    }
}
複製程式碼

正是由於以上的兩個原因,try-with-resources出現了。他不需要程式設計師去管理繁瑣的關閉資源,只需要在try-with-resources中的變數實現了AutoableColse介面就可以實現自動關閉資源的效果。

3. try-with-resources有什麼好處?

該語法的出現目的是讓程式設計師不需要再編寫繁瑣的try-finally,並且還能提高程式碼的可讀性。

4. try-with-resources 處理異常?

無論有沒有異常,都會首先執行close(),然後再判斷是否需要進入catch塊.

反編譯後的程式碼:

public static void startTest() {
       try {
           MyAutoCloseA a = new MyAutoCloseA();
           Throwable var33 = null;

           try {
               MyAutoCloseB b = new MyAutoCloseB();
               Throwable var3 = null;

               try { // 我們定義的 try 塊
                   a.test();
                   b.test();
               } catch (Throwable var28) { // try 塊中丟擲的異常
                   var3 = var28;
                   throw var28;
               } finally {
                   if (b != null) {
	                   // 如果 try 塊中丟擲異常,就將 close 中的異常(如果有)附加為壓制異常
                       if (var3 != null) {
                           try {
                               b.close();
                           } catch (Throwable var27) {
                               var3.addSuppressed(var27);
                           }
                       } else { // 如果 try 塊沒有丟擲異常,就直接關閉,可能會丟擲關閉異常
                           b.close();
                       }
                   }

               }
           } catch (Throwable var30) {
               var33 = var30;
               throw var30;
           } finally {
               if (a != null) {
                   if (var33 != null) {
                       try {
                           a.close();
                       } catch (Throwable var26) {
                           var33.addSuppressed(var26);
                       }
                   } else {
                       a.close();
                   }
               }

           }
       // 所有的異常在這裡交給 catch 塊處理
       } catch (Exception var32) { // 我們定義的 catch 塊
           System.out.println("Main: exception");
           System.out.println(var32.getMessage());
           Throwable[] suppressed = var32.getSuppressed();

           for(int i = 0; i < suppressed.length; ++i) {
               System.out.println(suppressed[i].getMessage());
           }
       }

   }
複製程式碼

注意:

  1. 在catch塊中,是訪問不了try-with-resources中的變數的
  2. try-with-recourse 中,try 塊中丟擲的異常,在 e.getMessage() 可以獲得,而呼叫 close() 方法丟擲的異常在e.getSuppressed() 獲得。
  3. try-with-recourse 中定義多個變數時,由反編譯可知,關閉的順序是從後往前。

參考資料:

www.cnblogs.com/IcanFixIt/p…

blog.csdn.net/weixin_4025…

docs.oracle.com/javase/tuto…

相關文章