OK, now that it’s just us API fanatics, imagine you need to call a stream read in an interface method implementation, but the interface doesn’t declare an I/O exception. For concreteness, suppose we have an interface:
interface Foo { public void bar(); }
and we want to implement a Foo that calls streaming I/O, as in:
public class IOFoo implements Foo { public void bar() { InputStream in = ...; ... int numBytes = in.read(buf); // throws IOException } }
A common example is the Java interface Runnable
, which has a run()
method which does not throw exceptions. Given that this is the basis for threads, the issue comes up all the time.
This won’t compile, because the call to the read method throws an I/O exception, which is a checked exception that is not declared on the run method. In fact, it can’t be declared on the run method, because the interface doesn’t declare an I/O exception. What I too often see is this broken workaround:
int numBytes = -1; try { numBytes = in.read(); } catch (IOException e) { throw new RuntimeException(e); }
What’s wrong here? There’s no way for anyone calling the bar()
method to recover the exception and handle it. You could document that it throws a RuntimeException
, but all kinds of problems can lead to a runtime exception being thrown, and there’s no way to tell which threw it. (Yes, you could encode it in the message, but that’s an even worse idea, as it’s very hard to maintain and code against.)
An alternative approach is to follow the pattern used by Java’s PrintWriter
class and buffer the exception then make it available to the caller. Here’s a simplified example that buffers a single exception:
public class IOFoo implements Foo { private IOException mException; public void bar() { InputStream in = ...; ... try { in.read(); // throws IOException } catch (IOException e) { mException = e; return; } } public IOException getIOException() { return mException; } }
That way, a caller can do this:
IOFoo f = new IOFoo(...); f.run(); if (f.getIoException() != null) throw (f.getIOException());
Now the context around the call to IOFoo’s run can catch the IOException. For instance, if this is in a method call, you can just declare the method to throw the checked IOException. Note that we need to declare f as an IOFoo, not just a Foo, because we call its getIOException method.
Java’s PrintWriter
keeps a list of exceptions that have been raised in calls to its methods. That’s because it keeps going after exceptions, assuming the client would rather they be silently ignored. I don’t think that’s such a great idea, for the obvious reason that there’s no telling what’s going to happen when I/O exceptions are just ignored.
It would be straightforward to set a flag that stops any further action once an exception has been raised.
The case I was actually using this in was for was writing a static method to serialize a tokenized language model. Visiting the n-grams requires an IntArrayHandler whose handle method is not declared to throw any checked exceptions. I wanted any embedded exception to be buffered and thrown by the top-level static method.
August 19, 2011 at 3:12 pm |
This is why I hate Interfaces. The only thing they can do is break.