A post about closing resources in Java. First though, an aside.
“Is it a good idea for destructors to throw?”
– Common C++ interview question
A quick bit of code can show us.
#include <iostream>
#include <stdexcept>
namespace {
class Foo {
public:
void someUsage() {
std::cout << "Using foo" << std::endl;
}
~Foo() {
std::cout << "Destroying foo" << std::endl;
throw std::runtime_error("Exception 2");
}
};
}
int main() {
std::cout << "Program started" << std::endl;
try {
Foo f;
f.someUsage();
throw std::runtime_error("Exception 1");
} catch (std::exception const & e) {
std::cout << "Caught exception!" << std::endl;
}
return 0;
}
Consider the above case where an object with a throwing destructor is
popped from the stack. We naïvely hope our catch block will save us, but
no, an exception has already thrown from another frame. We now have two
exceptions to deal with and our program calls std::terminate
(thanks
to Alan for a correction here – I
originally claimed this was UB).
Program started
Using foo
Destroying foo
terminate called after throwing an instance of 'std::runtime_error'
what(): Exception 2
Aborted (core dumped)
This StackOverflow thread provides an excellent discussion of this issue from a C++ perspective. Many of the answers and comments gel nicely with the remaining content of this post, so it is well worth a read (but only once you’re done here, obviously).
What of our safe, garbage collected languages, though? What approach do we take to closing resources not managed by the VM?
If at first you don’t succeed…
…try
, catch
, finally
. This is the typical resource usage pattern
in java – we acquire a resource (outside of the block – if we fail to
acquire it, no close
is required), use it in the try
block, perform
any desired exception handling in the catch
block, and then clean up
(usually invoking the close
method on the object in question) in the
finally
block, which is (roughly) guaranteed to be called, regardless
of what happens during try
and catch
.
Frequently the close
method is marked as throwing a checked exception.
This is annoying, as it means that even though we’ve performed some
resource cleanup, our finally
clause must also handle that exception
type (or our function must propagate it upwards). Typically, we get
around this by writing a closeQuietly
method (or using one from an
appropriate apache library) that catches the exception, suppresses it,
then perhaps logs that a resource has failed to close.
This is absolutely fine for single resource usages – like reading all the data out of a file, or performing an http request to a remote server.
A more complicated world
Why’d you have to go and make things so complicated?
– Avril Lavigne
Commonly we will want to write applications that keep several resources of different species open for the lifetime of our application (or at least, considerably longer than a single function call). Perhaps a collection of sockets, some shared memory accessed through JNI and a sprinkling of semaphores.
What happens when we want to cleanly stop our application? These
different resources will presumably be looked after by different pieces
of our object graph, so we will have to traverse that graph calling
close
where appropriate.
In a perverse world, our code might look like this:
public static void main(String[] args) {
final SharedMemory memory = new SharedMemory();
final CustomSocket customSocket = new CustomSocket();
try {
runApplication(memory, customSocket);
} catch (Exception e) {
e.printStackTrace(System.err);
} finally {
try {
memory.close();
} catch (SharedMemoryException e) {
e.printStackTrace(System.err);
}
try {
customSocket.close();
} catch (SocketCloseException e) {
e.printStackTrace(System.err);
}
}
}
This may be a rather extreme example. Neither resource implements
java.io.Closeable
(which would make things easier as we could extract
a single method), and both give feedback only in the form of a checked
exception. I’ve left the try/catch blocks in place to illustrate just
how annoying this is. How much worse this gets per different resource
species is left as an exercise to the reader – one hopes it is obvious
that this is another place that exception throwing fails to scale.
An alternative approach
We could mandate extension of Closeable
for all such resources, but
all this buys us is the ability to have just one static closeQuietly
function. That would be a start. Can we do better though?
Groans from the crowd. Is this another anti-exception post? You bet it is. Let’s consider this alternative interface:
package net.digihippo;
import java.util.Collection;
public interface Closeable {
public Collection<? extends Exception> close();
}
A couple of things to note here before we continue.
- The interface isn’t actually that important – here’s the previous program with resources that follow this pattern without implementing the interface:
public static void main(String[] args) {
final SharedMemory memory = new SharedMemory();
final CustomSocket customSocket = new CustomSocket();
try {
runApplication(memory, customSocket);
} catch (Exception e) {
e.printStackTrace(System.err);
} finally {
final List<Exception> closeProblems = new ArrayList<Exception>();
closeProblems.addAll(memory.close());
closeProblems.addAll(customSocket.close());
for (final Exception e: closeProblems) {
e.printStackTrace(System.err);
}
}
}
Exception
may not be the type that we want here. Once we have a return type, it’s possible that we just want aCollection
ofString
messages that tell us whyclose
has failed, rather than the considerably more expensiveException
. I chose it mostly because it was nearest, and possibly because having the stack could be useful for post-hoc rationalization.
These particular resources, in our example, share the program’s
lifetime, and so the only customer for the close
mechanism is the
programmer trying to correctly order a whole bundle of unrelated
shutdown
and close
calls. We will make their life a complete misery
if we take the lazy option of failing to close
by throwing – what on
earth do we expect our shutdown writer to do with it?
Conclusion
For resource library creators
C++ has given us a good hint – throwing from close
functions (and
other functions in that family, like stop
and shutdown
) is
unhelpful. In particular, throwing a custom checked exception type from
a close
method verges on malicious. It makes writing shutdown code
tedious, and tedium is not a fate we should wish on anyone. We should do
our brave shutdown hook writers a favour and provide our error output in
a sanitized format. If we really, really must throw (and by goodness we
need a superb excuse to do so), implementing java.io.Closeable
is
mandatory.
For shutdown writers
We are in a pretty poor place right now. From a brief scan of libraries
I use, those pesky resource library creators (Presumably this includes
the author? – Ed) have been out to get us – almost all of their close
methods throw checked exception types that we have no hope of recovering
from. Try to wrap their laziness as close to the source as possible; who
knows, perhaps the idea will take off, and our lives infinitesimally
improve.
Postscript
Having written no C++ for some time, I fashioned the top example without
having to look up what header std::runtime_error
was in, and the
program compiled and ran at the first attempt. Get in. Admittedly, it
didn’t do what I thought it would (my Foo
was optimized away), but
even that small victory made me smile. Having written this rather smug
post-script I now eagerly await -Wpedantic
like feedback from less
rusty C++ writers!