Try with resources in Java
Traditional try-catch-finally
With traditional try-catch, you can execute a block of code and handle any exceptions which may occur:
try {
// Do something
} catch (Exception e) {
// React to exceptions if they occurr
// in the try block
}Often it is useful to have also a finally block. It executes after try/catch, no matter whether there was an
exception or not. It is very useful, especially when working with resources, which need proper cleanup after being used.
When you use some resources, which are locked by your program (such as files or sockets and more), you need to make sure
you release them after you're done.
You need to do the cleanup no matter whether all ends well or whether there is an exception.
try {
// Open a resource
// Try to use a resource
} catch (Exception e) {
// React to exceptions if they occur
// in the try block
} finally {
// Close the resource when we're done
}Finally is a nice way to clean everything after we are done, but has its own limitations. There can be multiple places
where an exception may occur. That is when opening the resource, using it and even closing. That can result in a lot of
boilerplate code, which is hard to read and error prone. We are talking about nested try-catch statements combined
with null checks and more.
Most importantly, you need to remember to actually close all the resources and in the right order. That is, resources can have dependencies on each other, which you need to respect.
Fortunately, since Java 7, there is an easier way to manage resources automatically with try-with-resources, which
will close all the resources properly for you in the right order.
Try with resources
Using try-with-resources is easy. Instead of just plain:
try {
// Do something
} finally {
// Close my resource
}You create the resource directly after try keyword in parentheses, like this:
try (MyResource resource = new MyResource()) {
// Do something
} // Resource is automatically closed after this block endsYou basically create a resource, which exists only inside the try block and cannot be accessed afterward. When the
try block ends, the resource is automatically closed for you.
Now you ask what kind of resources you can use in try-with-resources and how does JVM know how to close them?
It is actually pretty simple. You can use all the resources, which implement
Closeable or
AutoCloseable
interface. It has only one method called close() which is automatically called for you once the try block finishes.
That means it is easy to provide your own custom resources. You can check all the classes implementing
Closeable or
AutoCloseable in their
JavaDoc.
Note that in the example above, we used a simple case of try-with-resources using just try block. Of course, you can
include both catch and finally blocks as well. In such case, the catch and finally blocks are executed after
all the resource have been closed.
Decompiled example
Let's look at a simple example using try-with-resources, which uses two resources and has just one operation:
try (FileReader fileReader = new FileReader("C:\\foo.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader)) {
bufferedReader.readLine();
}If we decompile this using Fernflower decompiler, we get something similar to this:
FileReader fileReader = new FileReader("C:\\foo.txt");
Throwable var2 = null;
try {
BufferedReader bufferedReader = new BufferedReader(fileReader);
Throwable var4 = null;
try {
bufferedReader.readLine();
} catch (Throwable var16) {
var4 = var16;
throw var16;
} finally {
$closeResource(var4, bufferedReader);
}
} catch (Throwable var18) {
var2 = var18;
throw var18;
} finally {
$closeResource(var2, fileReader);
}It is an interesting example of how try-with-resources works under the hood. You can check the
official specs for more detail.
Multiple resources
Inside the head of try-with-resources, you can declare more than one resource.
try (FileReader fileReader = new FileReader("C:\\foo.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader)) {
// Read some data!
}All the resources in the () parentheses are automatically closed for you. What's good to know is what is the order of
closing. The resources are closed in the reverse order of their declaration to avoid any dependency issues.
That is, if we have three resources like this:
try (resource1; resource2; resource3) {
}They are created in order of:
- resource1
- resource2
- resource3
However, they are closed in the reverse order:
- resource3
- resource2
- resource1
Java 9 improvements
Try with resources was introduced in Java 7. Until Java 9 you were forced to declare the resources and assign them a
value in the parentheses right after try. This is a lot of text and noise, which makes try-with-resources hard to
read, especially when using multiple resources.
try (FileReader fileReader = new FileReader("C:\\foo.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader)) {
// Read some data!
}Fortunately, since Java 9, you can just reference the name of the existing resource instead of its declaration and assignment. This is much more readable.
FileReader fileReader = new FileReader("C:\\foo.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
try (fileReader; bufferedReader) {
// Read some data!
}It is not shorter, but when you check try-with-resources, you can immediately see which resources it uses without all
the noise.
The limitation is, though that all the resources used need to be final of effectively final.
Implementing your own resources
The good news is that you can create your own resources, which can be used in try-with-resources. All you need to do
is to implement either java.io.Closeable or java.lang.AutoCloseable.
How are they different? Closeable is older, available since Java 5, AutoCloseable was introduced in Java 7 along
with try-with-resources. Since Java 7, Closeable actually extends AutoCloseable.
public interface AutoCloseable {
void close() throws Exception;
}
public interface Closeable extends AutoCloseable {
void close() throws IOException;
}As you can see, they are very similar. The signature of the close() method is different only in the exception thrown.
AutoCloseable can throw any Exception while Closeable throws IOException.
Note that when implementing an interface you can change the method signature in a way that it throws a different
exception. Or no exception at all. According to the JavaDoc, it is highly recommended to do so in this case. Declare
more specific exception in your implementation of close() method or no exception at all if it cannot fail.
There is one more difference, which you cannot see from the method's signature but from JavaDoc only. Closeable is
required to be idempotent, AutoCloseable not (although it is highly
recommended).
That means you should make sure calling close() multiple times would not cause any trouble.
IntelliJ IDEA integration
As usual, IDEA offers a nice support for try with resources feature. When you are using a resource, which implements
AutoCloseable interface, you can surround it with try-with-resources. Just press Alt + Enter
to open intention actions popup:
Using the same keyboard shortcut, IDEA allows you to convert traditional try-catch-finally to try-with-resources.
Alternatively, you can do the reverse operation using the same shortcut - convert try-with-resources to good old
try-catch-finally.
Conclusion
Try with resources is a useful alternative to traditional try-catch-finally when working with resources, which need to
be properly closed. The resource management is automatically handled for you. You can still use catch and finally
blocks, as usual, they get executed after the resources are closed.
If you are on Java 9 and later, you don't need to declare your resources directly in the try header, but you can use
previously declared resources, which are final or effectively final.
If you want to use your own resources, you can just implement Closeable or AutoCloseable interface and implement the
close() method.






Comments