Managing the life cycle of resources in Java 7: the new try-with-resources block 1

Java 7 includes a small language change to handle the destruction of resources in a try statement. The new code block, known as try-with-resources, looks like this:
try (MyResource myResource = new MyResource()) {
   // use myResource
}
MyResource is a class that implements java.lang.AutoCloseable. The Java Virtual Machine will call myResource.close() whenever the program leaves the try block (whether it exits normally or after throwing an exception).
Using well-known patterns for managing the lifecycle of resources helps in writing code that is readable, robust and maintainable. Until now, Java has lacked a consistent, built-in mechanism to do this. Programming in a garbage-collected language like Java also requires the programmer to manually dispose some objects such as files, sockets or database handlers. And relying on the garbage collector to do this (by implementing the finalize() method) is generally a bad idea–the garbage collector is non-deterministic! The most common way to handle this before Java 7 would be a try-finally block:
MyResource myResource = new MyResource();
try {
   // use myResource
} finally {
   myResource.close();
}
Other languages had resolved this problem before. In C++ it’s common to use the idiom known as “Resource Acquisition is Initialization” (RAII). RAII means that the programmer associates a new object in the stack with any resource requiring clean-up. The destructor of this object takes care of releasing the resource. Another example is C#, where programmers already benefited from the using statement, almost identical to the new Java try-with-resources block.
Here at RTI we realized that this little new Java feature goes a long way toward making your code cleaner. In the Request-Reply API, part of RTI Connext Messaging, you can wrap resources that you need to return to the middleware in a try-with-resources block. For example, reading loaned data from a Requester is as simple as:
import com.rti.connext.infrastructure.*;
import com.rti.connext.requestreply.*;
import myTypeSupport.RequestType;
import myTypeSupport.ReplyType;

Requester<RequestType, ReplyType> requester = ...;
RequestType request = ...;
requester.sendRequest(request);

try (Sample.Iterator<ReplyType> dataSamples = requester.receiveReplies()) {
    while(dataSamples.hasNext()) {
        Sample<ReplyType> dataSample = dataSamples.next();
        System.out.println("Received a new reply: " + dataSample.getData());
    }
}

When your application exits the try block, it automatically calls the Sample.Iterator.close() operation, which then returns the loaned data to the middleware (the equivalent to DataReader.return_loan(), in the Data Distribution Service (DDS) API).

Simple and elegant.

One comment

  1. In fact, this pattern is so useful that the new DDS-Java standard has adopted it by adding close methods for DDS entities and the above mentioned Sample.Iterator.close method. The close method in inherited from the Java 5 Closeable interface, which extends AutoCloseable in Java 7. Slick!

    Like

Submit a comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s