簡體   English   中英

使用 AutoCloseable 關閉多個資源(try-with-resources)

[英]Close multiple resources with AutoCloseable (try-with-resources)

我知道,如果資源實現了 AutoCloseable,您嘗試傳遞的資源將自動關閉。 到現在為止還挺好。 但是當我有幾個想要自動關閉的資源時,我該怎么辦。 套接字示例;

try (Socket socket = new Socket()) {
    input = new DataInputStream(socket.getInputStream());
    output = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
} 

所以我知道套接字會被正確關閉,因為它是在 try 中作為參數傳遞的,但是輸入和輸出應該如何正確關閉?

通過在括號中聲明所有資源,可以將 Try with resources 與多個資源一起使用。 查看文檔

來自鏈接文檔的相關代碼摘錄:

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());
        }
    }
}

如果您的對象沒有實現AutoClosableDataInputStream實現),或者必須在 try-with-resources 之前聲明,那么關閉它們的適當位置是在finally塊中,也在鏈接的文檔中提到。

別擔心,事情會“正常工作”。 來自Socket 的文檔

關閉此套接字也將關閉套接字的 InputStream 和 OutputStream。

我理解您擔心沒有在輸入和輸出對象上顯式調用close()並且實際上通常最好確保所有資源都由try-with-resources塊自動管理,如下所示:

try (Socket socket = new Socket();
     InputStream input = new DataInputStream(socket.getInputStream());
     OutputStream output = new DataOutputStream(socket.getOutputStream());) {
} catch (IOException e) {
} 

這會導致套接字對象“多次關閉”,但這不會造成任何傷害(這是通常建議將close()所有實現設為冪等的原因之一)。

除了上述答案,這是 Java 9 中添加的改進。

Java 9 try-with-resources 改進了編寫代碼的方式。 現在您可以在 try 塊之外聲明變量並直接在 try 塊內使用它們。因此,您將獲得以下好處。

  • 它在 try 之外聲明的資源(實際上是 final 或 final 的)可以通過自動資源管理自動關閉,只需將它們添加到 try 塊中即可。
    • 您不需要重新引用在 try 塊之外聲明的對象,也不需要像我們在 Java 7 中那樣手動關閉它們。
    • 它還有助於編寫干凈的代碼。

try-with-resource 我們可以在 Java 9 中這樣寫嗎?

public void loadDataFromDB() throws SQLException {
Connection dbCon = DriverManager.getConnection("url", "user", "password");
try (dbCon; ResultSet rs = dbCon.createStatement().executeQuery("select * from emp")) {
    while (rs.next()) {
        System.out.println("In loadDataFromDB() =====>>>>>>>>>>>> " + rs.getString(1));
    }
} catch (SQLException e) {
    System.out.println("Exception occurs while reading the data from DB ->" + e.getMessage());
}

}

這里自動資源管理會自動關閉兩個對象 dbCon & rs。

為了更好地理解上述定義用例列表,請找到一些 Java 7 代碼。

示例 1:

public void loadDataFromDB() throws SQLException {
Connection dbCon = DriverManager.getConnection("url", "user", "password");
try (ResultSet rs = dbCon.createStatement().executeQuery("select * from emp")) {
    while (rs.next()) {
        System.out.println("In loadDataFromDB() =====>>>>>>>>>>>> " + rs.getString(1));
    }
} catch (SQLException e) {
    System.out.println("Exception occurs while reading the data from DB ->" + e.getMessage());
} finally {
    if (null != dbCon)
        dbCon.close();
}

}

示例 2:

// BufferedReader is declared outside try() block
    BufferedReader br = new BufferedReader(new FileReader("C://readfile/input.txt"));

    try (BufferedReader inBr = br) {
            // ...
        }
    } catch (IOException e) {
        // ...
    }

在上面的示例中,您可以查看對象是否不在嘗試然后我們需要手動關閉或重新引用它。 同樣在 try 塊中有多個對象的情況下,它看起來很混亂,即使您在 try 內部聲明,也不能在 try 塊外部使用。

上面的答案很好,但在某些情況下,嘗試使用資源沒有幫助。

看看這個代碼示例:

private static byte[] getFileBytes(Collection<String> fileContent) throws CustomServiceException {
    try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(baos))) {
            for (String fileLine : fileContent) {
                writer.append(fileLine);
                writer.newLine();
            }
        }
        return baos.toByteArray();
    } catch (IOException e) {
        throw new CustomServiceException(SC_INTERNAL_SERVER_ERROR, "Unable to serialize file data.");
    }
}

在這個例子中,你不能只使用 try-with-resources 塊,因為 writer 必須將輸出緩沖區刷新到底層字符流,因此將 writer 放入 try-with-resources 塊不會起作用,方法將返回空數組.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM