Java Code Bytes: Be Resourceful With Try-With-Resources
When implementing a business case, we have to deal with resources. Check out this post to learn how to manage resources with the try-with-resources method in Java!
Join the DZone community and get the full member experience.
Join For FreeIt is very common that, while implementing a business case in Java, we have to deal with resources. In this context, a resource (such as a file or socket handle) is encapsulated in an object that we must close after they are used in order to release the resource. Traditionally, the onus was on the developer to close all the resources they created to avoid dependency collisions, generally in the following finally block. Failing to do so is not a compilation error, but it can easily lead to a leakage of resource. Though modern static code analysis tools are smart enough to give you a hint, not everyone uses them, and also, those alerts can be easily overlooked.
try-with-resources was first introduced in Java 7 and is a new way to handle (closing of) resources; it makes it easier dealing with resources by automatically taking care of the closing of resources in the correct order, which was used within a try-catch block.
Let's take a business case implementation where we need to fetch a given account's status code from a database. We will first see how it is done in the traditional way and, then, with more resourceful try-with-resources. Later, we will also see a more concise version of it, which was introduced in Java 9.
Resource Handling in the Traditional Way (pre-Java 7)
// Code is simplified and kept relevant to focus on the topic in hand.
public static int getAccountStatusCodeFromDataStore_traditional(String accountId) throws SQLException {
String accountStatusCodeQuery = getAccountStatusCodeQuery(accountId);
Statement statement = null;
ResultSet resultSet = null;
try {
statement = createStatementFromConnection();
resultSet = statement.executeQuery(accountStatusCodeQuery);
return getAccountStatusCodeFromResultSet(resultSet);
} finally {
if (resultSet != null)
resultSet.close();
if (statement != null)
statement.close();
}
}
As shown above, we have to add a finally block to deal with the closing of resource. We have to explicitly check for null before we call the close operation. Also, we have to maintain the logical order for the closing of resources. The code here is verbose; and, I have seen many cases where developers tend to forget to add the finally block for closing resource, which will lead to resource leaks.
As a side note, if exceptions are thrown here in both try block and finally block, the one thrown from finally block will suppress the other.
Resource Handling With try-with-resources in Java 7/8
The same block of code above is now implemented with try-with-resources, which will look like:
// Code is simplified and kept relevant to focus on the topic in hand.
public static int getAccountStatusCodeFromDataStore_tryWithResourcesJava7(String accountId) throws SQLException {
String accountStatusCodeQuery = getAccountStatusCodeQuery(accountId);
try (Statement statement = createStatementFromConnection();
ResultSet resultSet = statement.executeQuery(accountStatusCodeQuery)) {
return getAccountStatusCodeFromResultSet(resultSet);
}
}
In this example, you can see that the improved concisness of the code contributes to its overall readability. The resource management is done automatically here. We can have multiple resources in the try-with-resources statement. In that case, the resource declarations should be separated by a semicolon. These resources will be automatically closed, maintaining the logic order (the one declared last will be closed first etc.).
If exceptions are thrown here, in both the try-with-resources block and try block, the one thrown from try block will suppress the other. If required, we can retrieve the suppressed exceptions by calling the Throwable.getSuppressed method from the exception thrown by the try block.
Also, a try-with-resources statement can have catch and finally blocks. Any catch or finally block is run after the resources declared have been closed.
Resource Handling With try-with-resources in Java 9
A more concise version is introduced in Java 9. If we already have a resource declared as a final or effective final, we can use them in try-with-resources without creating any new variables. This allows us to take advantage of automatic resource management. The same block of code above, now implemented with more concise try-with-resources, will look like:
// Code is simplified and kept relevant to focus on the topic in hand.
public static int getAccountStatusCodeFromDataStore_tryWithResourcesJava9(String accountId) throws SQLException {
String accountStatusCodeQuery = getAccountStatusCodeQuery(accountId);
// declared explicitly final
final Statement statement = createStatementFromConnection();
// effective final
ResultSet resultSet = statement.executeQuery(accountStatusCodeQuery);
try (statement; resultSet) {
return getAccountStatusCodeFromResultSet(resultSet);
}
}
How It Works Behind the Scenes
The AutoCloseable interface was introduced with Java 7, and it was specifically designed to work with try-with-resources statements. The Closeable interface was introduced earlier with Java 5 and was modified to extend to the AutoCloseable. They both have this abstract method close, which the resource should implement and provide a valid implementation. We can use try-with-resources to close any resource that implements either AutoCloseable or Closeable. All of the JDK resource-based classes and interfaces are modified to extend either of these interfaces, making them compatible with try-with-resources out of the box.
However, if we are dealing with a resource that doesn't implement either of AutoCloseable or Closeable, we have to follow the traditional approach for closing the resource.
Key Takeaways
try-with-resources facilitates automatic resource management with no need to write an explicit finally block to deal with closing of resources. Here is the summary of the key takeaways about try-with-resources.
It helps in achieving more concise and legible code.
We can deal with multiple resources in the try-with-resources statement.
In Java 7/8, these resources must be declared in try-with-resources statement. The resources declared this way are implicitly final.
In Java 9, we can even use pre-created resources, given that the resources referenced are declared as a final or are effective final.
AutoCloseable or Closeable interfaces do behind the scenes magic — they work in tandem with try-with-resources statements.
Most of the resource-based classes and interfaces in JDK are modified to implement either AutoCloseable or Closeable, making them compatible with try-with-resources out of the box.
We can have our custom resources implement either of AutoCloseable or Closeable and make them work with try-with-resources statements.
Opinions expressed by DZone contributors are their own.
Comments