BT

Automatic Resource Management in Java

by Alex Blewitt on Aug 23, 2010 |

Part of Project Coin is the ability to deal with Automatic Resource Management, or simply ARM. The purpose is to make it easier to work with external resources which need to be disposed or closed in case of errors or successful completion of a code block. Consider the following trivial file-copy operation, from the Java Bytestream Tutorial:

FileInputStream in = null;
FileOutputStream out = null;
try {
  in = new FileInputStream("xanadu.txt");
  out = new FileOutputStream("outagain.txt");
  int c;
  while ((c = in.read()) != -1)
    out.write(c);
} finally {
  if (in != null)
    in.close();
  if (out != null)
    out.close();
}

Not only is there a lot of boiler plate, but the documentation for InputStream.close() suggests that it can throw an IOException. (An exception is far more likely on the OutputStream but in any case, there needs to be an outer catch or propagation in order to successfully compile this code.)

The lexical scope of the try-catch-finally block also requires the variable for FileInputStream in and FileOutputStream out to be declared lexically outside the block itself. (If they were defined inside the try block, then they wouldn't be available inside the catch or finally blocks.)

To eliminate this boilerplate code, and to tighten the lexical scoping of the resources used inside the block, a new addition has been made to the try block in the Java language. An initial specification of the try-with-resources blocks (or ARM blocks) was made available via an ininitial implementation, which has subsequently made its way into build 105 of JDK 7.

A new interface, java.lang.AutoCloseable, has been added to the proposed API, which defines a single method close() which throws Exception. This has been retro-fitted as a parent of java.io.Closeable, which means that all InputStream and OutputStream automatically take advantage of this behaviour. In addition, FileLock and ImageInputStream have also been fitted with the AutoCloseable interface.

This permits the above example to be written as:

try (
  FileInputStream in = new FileInputStream("xanadu.txt");
  FileOutputStream out = new FileOutputStream("outagain.txt")
) {
  int c;
  while((c=in.read()) != -1 )
    out.write();
}

At the end of the try block, whether by completion normally or otherwise, both the out and in resources will have close() called automatically. Furthermore, unlike our original example, both out.close() and in.close() are guaranteed to be executed. (In the original example, had in.close() thrown an exception, then the subsequent out.close() would not have been executed.)

There are some subtle aspects to this which are worth noting:

  • As it currently stands, a trailing semi-colon is not permitted after the final resource in the resources section.
  • The resources block is separated with () rather than the more usual {}, to separate it from the existing try body. If present, it must contain one or more resource definitions.
  • Each resource definition is of the form type var = expression; you can't have general statements in the resource block.
  • The resources are implicitly final; that is, they behave as if the final modifier is present. Any attempt to assign to the resource variable is a compile-time error.
  • The resources must be a subtype of AutoCloseable; it is a compile-time error if this is not the case.
  • The order of closure is the reverse order in which the resources are defined. In other words, in the refined example, out.close() is called prior to in.close(). This permits nested streams to be built and then closed from outer-in, which makes more sense than in order (e.g. for flushing buffers before the underlying stream is closed).
  • Each block may generate n+1 exceptions, where n is the number of resources. This can occur if the main body throws an exception, and each resource closure throws an exception as well. In this situation, the body's exception will be thrown, but the others will be added to the exception's suppressed exception list. They can be accessed via getSuppressedExceptions().
  • Exception stack traces may now have code prefixed with Suppressed: in these cases; the format of the serialized Throwable is now different as well. (This may impact Java 6 clients invoking remote services on Java 7 runtimes, or vice-versa.)
  • javax.swing and java.sql do not participate in ARM at the current time; classes need to opt-in by inheriting from AutoCloseable to be used by ARM. JDBC 4.1, if part of JDK 7, will support ARM but it's not clear when this will happen.

The ability to remove boilerplate code from the Java developer's work-flow is likely to be a minor productivity boost; but although it's available in JDK 7, it will be sometime before source code can be written to take advantage of that fact. Many libraries will need to be compiled to run against Java 6; and any use of the automatic resource management will only be applicable for code compiled with -target 7 (or similar). Once Java 6 is EOL and Java 8 has been released, then using ARM will become an automatic way of working.

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Hmmm..... by Clint Farleigh

I think I've seen this somewhere before... maybe about 5 years ago? :-)

About freaking time!!!!!!! by Matt Giacomini

.

Learning from others by Patrick Dreyer

One of the first lessons we as parents teach to our children is: Learn from others.
Why does this not apply to programming languages?

Try-catch-finally is about error handling and not about ARM.
Thus, why complicate the try-catch-finally instead introducing "using" as .NET is using it?
Have a look at msdn.microsoft.com/en-us/library/yh598w02%28VS.... it's simple, clear and straight forward.
This way we can even rename "java.lang.AutoCloseable" to "java.lang.Closeable" as it's not about auto-closing but about a clearly programmed/stated behavior being part of "using".

It's all about taking advantage of the fillets of each language.

Note: I'm not going into a debate .NET vs. Java - I won't.

Re: Learning from others by James Watson

Try-catch-finally is about error handling and not about ARM.


I have to agree that using the try keyword for this doesn't seem very good. I have to guess that the reason a new keyword wasn't used (such as 'using') is because the fear that existing code will not compile. Although, this did not prevent enum from being added which was more likely (I guess) to be used as a name in existing code.

Re: Learning from others by David Birdsall

what if it could be implemented using closures? Would coin's new syntax be able to do something similar to this, but without the extra boilerplate:

Closeable.close(new FileInputStream("xanadu.txt")) {
public void read(FileInputStream in) {
in.read();
}
});

...where Closeable.close is a static generic method that returned an object specifically used for closing after reading. Could even be a static import, but you'd still have to define the read(T) override.

At least it would be re-using another feature of the language (closures) and not introducing another keyword.

When I see the using() {} statement in C# it makes me think of blocks in languages like Ruby/Groovy.

Re: Learning from others by Rob Elliot

I'd have thought it would just be a method on Closeable. So you could do something like:

FileInputStream inputStream = new FileInputStream("xanadu.txt");
inputStream.with({ FileInputStream in ->
in.read();
});


Potentially if you made the instance variable final you wouldn't even need to pass it in as an argument to the lambda. The "with" method would call the closure in a try block and close itself cleanly in the finally block.

It does seem odd that this should be implemented at the same time as lambdas if lambdas would allow it to be implemented cleanly without further new syntax. Perhaps there's some subtlety to it that I'm missing.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

6 Discuss

Educational Content

General Feedback
Bugs
Advertising
Editorial
InfoQ.com and all content copyright © 2006-2014 C4Media Inc. InfoQ.com hosted at Contegix, the best ISP we've ever worked with.
Privacy policy
BT