try-with-resources語句


try-with-resources語句是一種聲明了一種或多種資源的try語句。資源是指在程序用完了之后必須要關閉的對象。try-with-resources語句保證了每個聲明了的資源在語句結束的時候都會被關閉。任何實現了java.lang.AutoCloseable接口的對象,和實現了java.io.Closeable接口的對象,都可以當做資源使用。
 
下面的例子讀取了一個文件的第一行。它使用了一個BufferedReader實例去讀取文件,BufferedReader是一種資源,用完之后必須關閉。
static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                  new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}
在這個例子中,try-with-resources語句種聲明的是BufferedReader資源。聲明語句緊跟着在try關鍵詞的圓括號里面。BufferedReader從Java SE7開始就實現了java.lang.AutoCloseable接口。因為BufferedReader聲明在了try-with-resources里面,所以無論try語句是正常結束還是異常結束(比方說BufferedReader.readLine方法拋出一個IOException異常),它都會被關閉。
 
在Java SE7之前,你可以用finally代碼塊來確保資源一定被關閉,無論try語句正常結束還是異常結束。下面的例子用finally代碼塊代替try-with-resources語句:

 

static String readFirstLineFromFileWithFinallyBlock(String path)
                                                    throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }
}
然而,在這個例子中,如果readLine和close方法都拋出異常,那么readFirstLineFromFileWithFinallyBlock方法最終會在finally代碼塊拋出異常,從try代碼塊里面拋出的那個異常被抑制住了。相比之下,readFirstLineFromFile方法中,如果try代碼塊和try-with-resources語句同時拋出異常,這個方法將會最終拋出try代碼塊里面的異常,try-with-resources語句里面拋出的異常被壓抑了。在Java SE7之后,你可以找回被壓抑的異常。參看后面的“被壓抑的異常”部分。
 
你可以在一個try-with-resources語句里面聲明多個資源。下面的例子展示了從一個名字為zipFileName的zip文件中檢索出里面所有文件的名稱,並創建一個文本文件存儲所有文件名稱。
public static void writeToFileZipFileContents(String zipFileName,
                                          String outputFileName)
                                          throws java.io.IOException {

    java.nio.charset.Charset charset =
        java.nio.charset.StandardCharsets.US_ASCII;
    java.nio.file.Path outputFilePath =
        java.nio.file.Paths.get(outputFileName);

    // Open zip file and create output file with
    // try-with-resources statement

    try (
        java.util.zip.ZipFile zf =
            new java.util.zip.ZipFile(zipFileName);
        java.io.BufferedWriter writer =
            java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
    ) {
        // Enumerate each entry
        for (java.util.Enumeration entries =
                                zf.entries(); entries.hasMoreElements();) {
            // Get the entry name and write it to the output file
            String newLine = System.getProperty("line.separator");
            String zipEntryName =
                ((java.util.zip.ZipEntry)entries.nextElement()).getName() +
                newLine;
            writer.write(zipEntryName, 0, zipEntryName.length());
        }
    }
}
在這個例子中,try-with-resources語句包含了兩個用分號隔開的聲明:ZipFile和BufferedWriter。當代碼塊中代碼終止,不管是正常還是異常,BufferedWriter和ZipFile對象的close方法都會自動按聲明的相反順序調用。
 
下面的例子用try-with-resources語句自動關閉一個java.sql.Statement對象:
public static void viewTable(Connection con) throws SQLException {

    String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES";

    try (Statement stmt = con.createStatement()) {
        ResultSet rs = stmt.executeQuery(query);

        while (rs.next()) {
            String coffeeName = rs.getString("COF_NAME");
            int supplierID = rs.getInt("SUP_ID");
            float price = rs.getFloat("PRICE");
            int sales = rs.getInt("SALES");
            int total = rs.getInt("TOTAL");

            System.out.println(coffeeName + ", " + supplierID + ", " +
                              price + ", " + sales + ", " + total);
        }
    } catch (SQLException e) {
        JDBCTutorialUtilities.printSQLException(e);
    }
}
例子中的資源java.sql.Statement是JDBC 4.1及其后面版本的一部分。
 
注意:try-with-resources語句也可以像普通的try語句一樣,有catch和finally代碼塊。在try-with-resources語句中,任何的catch和finally代碼塊都在所有被聲明的資源被關閉后執行。
 
被壓抑的異常
 
try-with-resources語句相關聯的代碼塊可能會拋出異常。在writeToFileZipFileContents例子中,try代碼塊中可能會拋出異常,並且有高達兩個異常可能會在try-with-resources語句拋出,當試圖去關閉ZipFile和BufferedWriter對象的時候。如果在try代碼塊中拋出一個異常,同時在try-with-resources語句中拋出一個或多個異常,那么在try-with-resources語句中拋出的異常就被壓抑了,並且最終在writeToFileZipFileContents方法拋出的異常就是try代碼塊中拋出的那個異常。你可以通過被try代碼塊拋出的異常的Throwable.getSuppressed方法找回被壓抑的異常。
 
實現了AutoCloseable或Closeable接口的類
 
看  AutoCloseable 和  Closeable 接口的javadoc,看看實現了它們的類都有哪些。Closeable接口繼承了AutoCloseable接口。不同之處在於,Closeable接口的close方法拋出的是IOException異常,AutoCloseable接口的close方法拋出的是Exception異常。 因此,AutoCloseable的子類可以重寫close方法的行為,拋出指定的異常,比如IOException異常,甚至可以不拋出異常。

 原文地址

轉自:http://leaforbook.com/blog/jexception/translate/tryResourceClose.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM