I saw this example on the web and in the Book "Effective Java" (by Joshua Bloch).
try(BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))){
writer.write(str); // do something with the file we've opened
}
catch(IOException e){
// handle the exception
}
There is no problem with this example, BufferedWriter
which will automatically get closed and that, in turn, will close the FileWriter
; however, in other case, if we declare 2 nested resources this way:
try (AutoClosable res = new Impl2(new Impl1())) {... }
I guess it might happen that new Impl1()
performs fine, but new Impl2()
crashes, and in this case Java would have no reference to the Impl1
, in order to close it.
Shouldn't it be a better practice to always declare multiple resources independently (even if not required in this case), like this?
try(FileWriter fw = new FileWriter(fileName);
BufferedWriter writer = new BufferedWriter(fw)){ ... }
The try -with-resources statement is a try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try -with-resources statement ensures that each resource is closed at the end of the statement.
A resource is an object to be closed at the end of the program. As seen from the above syntax, we declare the try-with-resources statement by, declaring and instantiating the resource within the try clause. specifying and handling all exceptions that might be thrown while closing the resource.
The try-with-resources statement is a try statement with one or more resources duly declared. Here resource is an object which should be closed once it is no more required. The try-with-resources statement ensures that each resource is closed after the requirement finishes.
The resources are automatically closed when using try-with-resource block. As part of this process it will also invoke flush automatically.
After some searching I was able to find this article: https://dzone.com/articles/carefully-specify-multiple-resources-in-single-try
By definition JLS 14.20.3 a ResourceList
consists of Resource
s separated by ;
. Based on that we can conclude that a nested initialization like AutoClosable res = new Impl2(new Impl1())
is a single resource. Because of that rules defined for try-with-resources
with multiple resources won't apply here, important ones being:
Resources are initialized in left-to-right order. If a resource fails to initialize (that is, its initializer expression throws an exception), then all resources initialized so far by the try-with-resources statement are closed. If all resources initialize successfully, the try block executes as normal and then all non-null resources of the try-with-resources statement are closed.
Resources are closed in the reverse order from that in which they were initialized. A resource is closed only if it initialized to a non-null value. An exception from the closing of one resource does not prevent the closing of other resources. Such an exception is suppressed if an exception was thrown previously by an initializer, the try block, or the closing of a resource.
What is more, Implt1#close()
won't be called unless it is explicitly called inside of Impl2#close()
In short, it is better to declare multiple resources in separate statements separated with ;
, like so:
try(Impl1 impl1 = new Impl1();
Impl2 impl2 = new Impl2(impl1))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With