Java 使用 AutoCloseable 关闭多个资源(try-with-resources)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30553139/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Close multiple resources with AutoCloseable (try-with-resources)
提问by asmb
I know that the resource you pass with a try, will be closed automatically if the resource has AutoCloseable implemented. So far so good. But what do I do when i have several resources that I want automatically closed. Example with sockets;
我知道,如果资源实现了 AutoCloseable,您尝试传递的资源将自动关闭。到现在为止还挺好。但是当我有几个想要自动关闭的资源时,我该怎么办。套接字示例;
try (Socket socket = new Socket()) {
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
}
So I know the socket will be closed properly, because it's passed as a parameter in the try, but how should the input and output be closed properly?
所以我知道套接字会被正确关闭,因为它在 try 中作为参数传递,但是输入和输出应该如何正确关闭?
回答by augray
Try with resources can be used with multiple resources by declaring them all in the parenthesis. See the documentation
通过在括号中声明所有资源,可以将 Try with resources 与多个资源一起使用。查看文档
Relevant code excerpt from the linked documentation:
来自链接文档的相关代码摘录:
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());
}
}
}
If your objects don't implement AutoClosable
(DataInputStream
does), or must be declared before the try-with-resources, then the appropriate place to close them is in a finally
block, also mentioned in the linked documentation.
如果您的对象没有实现AutoClosable
( DataInputStream
does),或者必须在 try-with-resources 之前声明,那么关闭它们的适当位置是在finally
块中,也在链接的文档中提到。
回答by Paulo
Don't worry, things will "just work". From Socket's documentation:
别担心,事情会“正常工作”。来自Socket 的文档:
Closing this socket will also close the socket's InputStream and OutputStream.
关闭此套接字也将关闭套接字的 InputStream 和 OutputStream。
I understand your concern about not explicitly calling close()
on the input and output objects and in fact it's generally better to ensure all resources are automatically managed by the try-with-resources
block, like this:
我理解您对不显式调用close()
输入和输出对象的担忧,事实上,确保所有资源都由try-with-resources
块自动管理通常会更好,如下所示:
try (Socket socket = new Socket();
InputStream input = new DataInputStream(socket.getInputStream());
OutputStream output = new DataOutputStream(socket.getOutputStream());) {
} catch (IOException e) {
}
This would have the effect that the socket object would be "closed multiple times", but that should not do any harm (this is one of the reasons why it's generally advised that all implementations of close()
be made idempotent).
这会导致套接字对象“多次关闭”,但这不会造成任何伤害(这是通常建议将所有实现都close()
设为幂等的原因之一)。
回答by Dzmitry Hubin
Answers above are great but there are some cases when try-with-resources doesn't help.
上面的答案很好,但在某些情况下,尝试使用资源没有帮助。
Take a look at this code example:
看看这个代码示例:
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.");
}
}
In this example u can't just use try-with-resources block cause writer has to flush the output buffer to the underlying character stream so placing writer into try-with-resources block won't do the trick and method will return empty array.
在这个例子中,你不能只使用 try-with-resources 块,因为 writer 必须将输出缓冲区刷新到底层字符流,因此将 writer 放入 try-with-resources 块不会起作用,方法将返回空数组.
回答by Shivang Agarwal
In addition to the above answers, This is the improvement added in Java 9.
除了上述答案,这是在 Java 9 中添加的改进。
Java 9 try-with-resources makes an improved way of writing code. Now you can declare the variable outside the try block and use them inside try block directly.because of this you will get following benefits.
Java 9 try-with-resources 改进了编写代码的方式。现在您可以在 try 块之外声明变量并直接在 try 块内使用它们。因此,您将获得以下好处。
- The Resources which it declared outside try( which is effectively final or final) can be automatically close by automatic resource management by just adding them in the try block.
- You no need to re-refer objects declared outside try block nor need to close them manually as we need to do in Java 7.
- It also helps to write clean code.
- 它在 try 之外声明的资源(实际上是 final 或 final 的)可以通过自动资源管理自动关闭,只需将它们添加到 try 块中即可。
- 您不需要重新引用在 try 块之外声明的对象,也不需要像我们在 Java 7 中那样手动关闭它们。
- 它还有助于编写干净的代码。
try-with-resource can we write like this in Java 9.
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());
}
}
}
Here automatic resource management will automatically close both the objects dbCon & rs.
这里自动资源管理会自动关闭两个对象 dbCon & rs。
For the better understanding of the list of above define use cases please find some Java 7 code.
为了更好地理解上述定义用例列表,请找到一些 Java 7 代码。
Example 1:
示例 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();
}
}
}
Example 2:
示例 2:
// BufferedReader is declared outside try() block
BufferedReader br = new BufferedReader(new FileReader("C://readfile/input.txt"));
try (BufferedReader inBr = br) {
// ...
}
} catch (IOException e) {
// ...
}
In the above samples you can see if the object is ouside try then either we need to close manually or re-refer it. Also in the case of multiple objects in the try block, it looks messy and even if you declared inside try then you can't use outside try block.
在上面的示例中,您可以查看对象是否不在尝试然后我们需要手动关闭或重新引用它。同样在 try 块中有多个对象的情况下,它看起来很混乱,即使您在 try 内部声明,也不能在 try 块外部使用。