With some frequency I find myself writing APIs that offer an Iterator<Foo> which is backed by a network connection. The implementation opens a network connection, reads information off the stream, and deserializes that information into Foos to pass on to the caller. Unfortunately there is always the possibility of an IOException and also the need to close the network connection gracefully (that can be made automatic when the caller reads the last Foo, but what if that doesn’t happen?).
There are already a couple of questions (here and here) about how to deal with checked exceptions that would be thrown in an implementation of Iterator, and the accepted advice is “wrap them in unchecked RuntimeExceptions”. Meanwhile to allow closing the network connection we can implement Closeable. So we end up with something like this for a well-behaved exception-checking caller:
Iterator<Foo> iter = null;
try {
iter = getFooIterator();
while(iter.hasNext()) {
Foo foo = iter.next();
// do something with foo
}
}
catch(RuntimeException e) {
if(e.getCause() instanceof IOException) {
// do something with the IOException
}
else throw e;
}
finally {
if(iter instanceof Closeable) try { ((Closeable)iter).close(); } catch(IOException e) {}
}
And it seemed like such a nice idea to implement Iterator. Is there a better way?
IMO the first step would be to wrap it up in an implementation- or app-specific exception, eliminating the need for catching generic
RuntimeExceptions or checking the root cause.I’d consider a specific implementation to avoid the closeable check and to wrap up the
IOException.I probably wouldn’t give it method to make the boilerplate go away, but I’d be tempted; roughly: