- Is it correct that if I'm using a resource that implements the interface java.lang.AutoCloseable I don't need to close it in the finally block and it will be closed even if an exception will be thrown?
Yes.
if so, Is there a precondition that must exist? (e.g. creating the resource inside a try block?)
The resource must be created within the try-with-resources statement (see below).
- What does the try-with-resources statement exactly mean?
Here's a try-with-resources statement:
try (FileReader fr = FileReader(path)) {
// use fr here
}
Note how the initialization of the FileReader
is in the try
(in the new ()
part). That's how the statement knows what needs to be closed later.
(More in the tutorial, though I don't like their first example because it relies on A) The fact that the BufferedReader
constructor never throws, and B) The fact that BufferedReader
will close the FileReader
when the BufferedReader
is closed. Those are true for BufferedReader
, but it's a poor example in the general case.)
The full gritty details, including a translation of what a try-with-resources
looks like in the old try/catch/finally
format, are in the specification.
Note that you can create multiple resources in the statement; they're closed in reverse order of creation:
try (
FileReader fr =
new FileReader(fileName);
NiftyThingUsingReader nifty =
new NiftyThingUsingReader(fr)
) {
// ...use `nifty` here
}
Although you could write:
try (
NiftyThingUsingReader nifty =
new NiftyThingUsingReader(new FileReader(fileName))
) {
// ...use `nifty` here
}
...you'd have to know for sure that NiftyThingUsingReader(FileReader)
never throws an exception, and that NiftyThingUsingReader#close
will close the underlying FileReader
, because it will not be handled by the try-with-resources itself. If you're unsure, keep them separate, so that the try-with-resources statement closes the FileReader
even if the NiftyThingUsingReader(FileReader)
constructor throws, and even if NiftyThingUsingReader#close
doesn't close it.
The resources don't have to be relying on each other (directly); for instance, this is a fairly common situation where you want both the input and output to be handled:
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());
}
}