Java Reference
In-Depth Information
This creates the question of what to do with the closeException that may be thrown. If an exception is
thrown while working with the resource, and then another exception is thrown while closing the resource,
then what? If you throw closeException , the original exception (which is probably actually useful) is
lost. The usual solution was to simply ignore the closeException , often hidden inside a method called
something like closeQuietly(InputStream in) . This method could also then ignore null values. This made
the code significantly shorter and somewhat more readable:
InputStream in = null;
try {
in = acquireInputStream();
// Do something
} finally {
in = null;
There are some subtle problems with this code, however. At first glance, they may seem trivial, but they
won't be trivial when they crop up in your production code. The most significant of these subtle problems
is that this code ignores any exception that occurs on close, which is exactly when buffered streams,
compression streams, and cryptographic streams will throw their exceptions. This code will silently discard
those exceptions, leaving the calling code (and the debugging developer) to think everything is just fine.
This code pattern also still leaks the resource's variable into the surrounding scope. If you forgot to assign
the resource to null , you would then leak the object itself, preventing its timely garbage collection. The
resource handling can also get lost or confused easily if there are catch clauses attached to the try, as well,
and multiple resources would require nesting these structures within each other. The whole thing just has a
kind of ugliness to it still.
In an attempt to resolve this ugliness, Java 7 introduced the “try-with-resources” syntax structure.
This allows you to declare your resources at the start of the try block, and it would automatically close the
resources. You can assign anything that implements java.lang.AutoCloseable as a resource. That resource
will be closed automatically when the try block completes. If an exception is thrown on close, then
the exception will be propagated up to the caller. If there was already an exception thrown and an
additional exception is thrown on close, than that additional exception is attached to the first as a
suppressed exception: the stack trace will reveal the original exception as the primary cause, and the
close exception as an additional suppressed exception. As an added benefit, you have clearly delimited
boundaries for your variables, and the compiler guarnatees that they will be closed when you exit the block.
Overall, this gives the kind of exception handling that people are looking for, and the code looks like this:
public void closeQuietlyTryWithResource() {
try(InputStream in = acquireInputStream()) {
// Do something
} catch(IOException exception) {
// Handle exception, which may include close exceptions
Search WWH ::

Custom Search