Philip Potter

Sneakily throwing checked exceptions

Posted on 28 April 2012

I was reading the Clojure source code the other day when I noticed this curious snippet in LispReader.java:

static public int read1(Reader r){
    try
        {
        return r.read();
        }
    catch(IOException e)
        {
        throw Util.sneakyThrow(e);
        }
}

I immediately thought to myself: “what does sneakyThrow do?” It looks like it is a magic way to throw a checked exception without needing a throws declaration. But how does it work?

First, a little background. Checked exceptions are effectively a static analysis tool: there are no runtime checks on checked exceptions. Rather, javac will refuse to compile code where a checked exception is thrown with no catch block to catch it nor throws declaration to declare its propagation.

It’s possible to throw a checked exception using bytecode manipulation, or Thread.stop(Throwable), and these techniques have been known for at least a decade. However bytecode manipulation is messy, and Thread.stop(Throwable) has been deprecated for at least a decade too. Is there a pure-Java way to throw a checked exception sneakily?

C-family languages normally provide typecasts, a trapdoor to escape their static typing system when you think it is more hindrance than help. So a first attempt might go something like throw (RuntimeException) e;. However if you try this in the above code, you will get a ClassCastException at runtime, because IOException is not an instance of RuntimeException. It would seem that there is no pure-Java way to throw a checked exception.

So how does sneakyThrow work? Here it is, in all its glory:

/**
 * Throw even checked exceptions without being required
 * to declare them or catch them. Suggested idiom:
 * throw sneakyThrow( some exception );
 */
static public RuntimeException sneakyThrow(Throwable t) {
    // http://www.mail-archive.com/javaposse@googlegroups.com/msg05984.html
    if (t == null)
        throw new NullPointerException();
    Util.sneakyThrow0(t);
    return null;
}

@SuppressWarnings("unchecked")
static private  void sneakyThrow0(Throwable t) throws T {
    throw (T) t;
}

That link in the comments gives credit to Reinier Zwitserloot who, as far as I know, had the first mention of this technique in 2009 on the java posse mailing list.

What we have here is a severe abuse of Java. Util.sneakyThrow(t) calls Util.sneakyThrow0; then within sneakyThrow0() we cast to the parameterized type T. In this case that type is RuntimeException. At runtime, however, the generic types have been erased, so that there is no T type anymore to cast to, so the cast disappears.

In other words, we’ve managed to convince the compiler and the runtime that they’re seeing different things. The compiler sees the code with the cast:

throw (RuntimeException) t;

so it allows the now-unchecked exception to propagate. The runtime doesn’t see the generic types, so it sees no cast:

throw t;

and therefore it doesn’t complain about a ClassCastException.

There was one last nagging thought I had about the original code:

throw Util.sneakyThrow(e);

Given that Util.sneakyThrow(e) throws the exception itself, why does the calling code also use throw? The answer is, once more, to make the compiler happy. Without the throw, the compiler will demand a return statement afterwards.


Reinier Zwitserloot added this functionality to Project Lombok as the @SneakyThrows annotation, so now you can propagate checked exceptions sneakily with minimal boilerplate. The @SneakyThrows page also summarizes neatly some use-cases for why you would ever actually want to throw a checked exception:

  • You are calling a method which literally can never throw the exception that it declares. The example given is new String(someByteArray, "UTF-8"), which declares that it throws UnsupportedEncodingException but UTF-8 is guaranteed by the Java spec to always be present.
  • You are implementing a strict interface where you don’t have the option for adding a throws declaration, and yet throwing an exception is entirely appropriate — the canonical example is Runnable.run(), which does not throw any checked exceptions.

The first case is clear — the throws declaration is a nuisance and any solution to silence it with minimal boilerplate is welcome.

The second case has one common alternative: wrapping the checked exception in a RuntimeException so that you can throw it. Both approaches will have their critics. Wrapping an exception just to gain the privelege of throwing it results in a stacktrace with spurious exceptions which contribute no information about what actually went wrong. On the other hand, throwing checked exceptions may violate the principle of least surprise; it will no longer be enough to catch RuntimeException to be able to guarantee catching all possible exceptions.

It will be up to any given project to decide which is the lesser of two evils and establish a standard on their codebase.