我知道,如果资源实现了AutoCloseable,那么您通过尝试传递的资源将自动关闭。到目前为止一切顺利。但是,当我想要自动关闭几个资源时,我该怎么办呢?
try (Socket socket = new Socket()) {
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
}
所以我知道套接字将被正确地关闭,因为它作为一个参数在尝试中传递,但是如何正确地关闭输入和输出?
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
(DataInputStream
可以),或者必须在使用资源进行尝试之前声明,那么关闭它们的适当位置是在finally
块中,也在链接文档中提到。
别担心,事情会"刚刚好"。来自Socket的文档:
关闭此套接字也将关闭套接字的输入流和输出流。
我理解你对没有在输入和输出对象上显式调用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内部声明,你也不能在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块中不起作用,并且方法将返回空数组。