Thursday, October 27, 2011

Java, How to throw undeclared checked exception

Usually when you have caught checked exception (e.g. IOException or Interrupted) you have to wrap it in RuntimeException to rethrow it without declaring exception in method signature. But with help of generic you can now easily break java rules and throw say IOException exception from a method which has no throws declaration.

Code below will allow to throw anything anywhere.
public class AnyThrow {

    public static void throwUncheked(Throwable e) {
        AnyThrow.<RuntimeException>throwAny(e);
    }
   
    @SuppressWarnings("unchecked")
    private static <E extends Throwable> void throwAny(Throwable e) throws E {
        throw (E)e;
    }
}

I would say, it is very sad outcome from Java implementation of generics. While benefits from checked exception are arguable, they have provided some rules you were able rely upon.  But not any more, thanks to generics.
But it is that it is :)




7 comments:

  1. i think u can still throw only uncheckedexceptions, else the cast (E)e would fail, isn't it?

    ReplyDelete
  2. It works, I have tested it :)

    Trick is, E is a generic. At runtime erasure takes place and E is replaced by Throwable (a bound for E). Forcing template agrument at throwUnchecked() does really add any code to compile class, but let's us skip throws declaration.

    ReplyDelete
  3. Nice, I added a twist on it:
    http://www.eishay.com/2011/11/throw-undeclared-checked-exception-in.html
    So the compiler will know you're breaking the flow.

    ReplyDelete
  4. Famous trick. Also you can create default constructor like this:

    public Some() throws Exception {
    throw new Exception();
    }

    and execute from reflection:

    Some.class.newInstance();

    Result will be the same as yours.

    ReplyDelete
  5. it looks interesting but to write program in such manner would be a way to get a lot of pain imho

    ReplyDelete
  6. Well, my Eclipse doesn't allow me to throw anything but a RuntimeException or its descendant this way. And with such a limitation it doesn't break any java rules on exceptions handling.
    Did you try this code with, say, IOException?

    ReplyDelete
  7. Oops, sorry didn't get you quite right.

    It works OK, and throws anything if being called , say like "AnyThrow.throwUncheked(new IOException())"

    ReplyDelete