In-depth look at Java try-with-resource
Resource handling
Before Java 7 working with IO resource (files, JDBC) was tedious, you had to close the resource manually. Most of these operations with resources can throw exceptions. Whether the exception was thrown or try block completed without exception resource should be closed.
Pre Java 7 example:
Before Java 7 resource closing was mostly done using finally.
Post Java 7 example:
As you can see Java 7 sample is a lot shorter, it lacks finally clause.
In Java 7 resource closing can be delegated to the resource. For this to work you must initialize resource after try clause, in parenthesis. Regardless if an exception was thrown or try block completed without exception, close method is called.
Implementing your own auto closable resource
At first, I thought that this feature was really cool.
My second thought was “What kind of sorcery is this”. Under the hood, it is really simple,
resource must implement AutoCloseable interface.
This interface has only single method void close() throws Exception
.
MyFirstAutoCloseableResource.java:
Main.java:
Executing this code should print:
MyFirstAutoCloseableResource: doing stuff
MyFirstAutoCloseableResource: closing resource
To demonstrate execution order when an exception occurs I have updated doSomething method.
MyFirstAutoCloseableResource: doing stuff
MyFirstAutoCloseableResource: closing resource
Handling exception
As you can see resource was closed before handling the exception.
Tip! While implementing close method you should specify a more specific type of Exception. Also, you can specify RuntimeException, this makes catch block optional.
Exception propagation differences
Finally resource closing
When using old style of resource closing catch block exceptions are swallowed, when the exception occurs in finally block and only exception from finally is thrown.
Output:
Throwing exception in try block
Throwing exception in finally block
java.lang.RuntimeException: Finally block exception
try-with-resource
FirstAutoCloseableResource.java
Main.java
Output:
Throwing exception from doSomething()
Throwing exception from close()
java.lang.RuntimeException: DoSomething() exception
In this case exception from action was propagated instead of close method exception. Using try-with-resource you can retrieve exception from close() method by calling getSuppressed() on doSomething() exception.
Multiple resources
You can define multiple resources in try statement, Java will handle closing for you.
FirstAutoCloseableResource.java:
SecondAutoCloseableResource.java:
MultipleResources.java:
Output:
FirstAutoCloseableResource: Executing doSomething()
SecondAutoCloseableResource: Executing doSomething()
SecondAutoCloseableResource: Closing resource
FirstAutoCloseableResource: Closing resource
Also, you should keep in mind that Java closes resources in backward declaration order. It will start closing resources from last to first.
Java 9 additions
Before Java 9 you could not initialize AutoCloseable resource outside try statement. Java 9 allows us to define auto closable resources outside try scope.
ResourceOutsideTry.java:
This might be useful in cases when the resource was passed to function or using dependency injection. But this has one downside, after cleanup you can still access the resource and invoke methods on it, this could lead to undesirable behavior.
Conclusion
Try-with-resource reduces boilerplate code and helps to avoid human error in case we forget to close resource. I hope you learned something from this long-winded blog post about this simple feature.
If you have any questions feel free to leave a comment.