68

我知道如果资源已实现 AutoCloseable,您尝试传递的资源将自动关闭。到目前为止,一切都很好。但是,当我有几个想要自动关闭的资源时,我该怎么办。带有套接字的示例;

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

所以我知道socket会正常关闭,因为在try中是作为参数传递的,但是应该如何正确关闭输入输出呢?

4

4 回答 4

85

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

如果您的对象没有实现AutoClosable( DataInputStreamdoes),或者必须在 try-with-resources 之前声明,那么关闭它们的适当位置是在一个finally块中,也在链接文档中提到。

于 2015-05-31T02:10:43.250 回答
28

别担心,事情会“正常工作”。来自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()设为幂等的原因之一)。

于 2015-12-04T12:54:49.003 回答
6

除了上面的答案,这是 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 块之外使用。

于 2018-07-24T12:00:06.503 回答
2

上面的答案很好,但在某些情况下 try-with-resources 没有帮助。

看一下这个代码示例:

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 块不会起到作用,并且方法将返回空数组.

于 2018-05-16T15:02:28.193 回答