Since it’s release about a year ago, a lot of buzzing has been going on about new language features in Java 7 - least of
which about the new try
-with-resources statement.
Here’s how you can implement it within Scala.
In case you don’t know, let’s quickly explain how the try
-with-resources statement works.
Here’s a trivial example:
try (PrintWriter out = new PrintWriter(new File("file"))) {
out.println("Hello world!\n");
}
Doesn’t look like much, but this statement provides two features:
out.close()
will be called as soon as thetry
-block is left, even if the block terminates with aThrowable
.- In case the
try
-block terminates with a throwablex
and the call toclose()
terminates with another throwabley
, then the throwabley
gets added to the throwablex
as a suppressed throwable by callingx.addSuppressed(y)
.
Suppressed exceptions will be marked as such whenever a stack trace is printed via Throwable.printStackTrace()
, so
they leave a trace for you to follow.
When the compiler sees the previous statement, it will effectively rewrite it to (see The Java Language Specification, Java SE 7 Edition, section 14.20.3.1):
{
final PrintWriter out = new PrintWriter(new File("file"));
Throwable t = null;
try {
out.println("Hello world!\n");
} catch (Throwable x) {
t = x;
throw x;
} finally {
if (out != null) {
if (t != null) {
try {
out.close();
} catch (Throwable y) {
x.addSuppressed(y);
}
} else {
out.close();
}
}
}
}
You could actually think of the try
-with-resources statement as an implementation of the loan pattern:
The resource within the parenthesis of the try
-statement gets “loaned” to the try
-block for processing, after which
it gets automatically “reclaimed” by calling AutoCloseable.close()
.
Scala doesn’t have a try-with-resources statement, but thanks to closures, you can easily implement it using the following code:
import java.io._
class Loan[A <: AutoCloseable](resource: A) {
def to[B](block: A => B) = {
var t: Throwable = null
try {
block(resource)
} catch {
case x => t = x; throw x
} finally {
if (resource != null) {
if (t != null) {
try {
resource.close()
} catch {
case y => t.addSuppressed(y)
}
} else {
resource.close()
}
}
}
}
}
object Loan {
def loan[A <: AutoCloseable](resource: A) = new Loan(resource)
}
As you can see, this is an exact implementation of Java’s try
-with-resources statement for Scala.
Getting back to the initial example, you can now translate it to Scala as follows:
import java.io._
import Loan._
loan (new PrintWriter(new File("file"))) to (_ println "Hello world!\n")
See how Scala’s DSL support makes a nicely readable loan-pattern statement? Now you don’t need to copy-paste this code if you don’t mind adding a dependency to your Maven build. Just add the following dependency:
<dependency>
<groupId>net.java.truecommons</groupId>
<artifactId>truecommons-io</artifactId>
<version>1.0</version>
</dependency>
or directly download the JAR from Maven Central and explore its other features. Source code and Javadoc are available on Maven Central, too.
Enjoy!