开发者

Magic Exception thrower without declaring throws Exception

I want a method that can throw any Throwable including sub classes of Exception. Ive got something that takes an exception, stashes it in a thread local, then invokes a class.newInstance. That class ctor declares that it throws Exception then takes the threadlocal and throws it. Problem is it does not work for the two declared Exceptions thrown by Class.newInstance() namely IllegalAccessException and InstantiationException.

Im guessing any other method using some sun.* class is just a hack and not really reliable.

Wrapping is not an option because that means catchers are catching a diff type and that's just too simple and boring...

    static public void impossibleThrow(final Throwable throwable) {
    Null.not(throwable, "throwable");
    if (throwable instanceof RuntimeException) {
        throw (RuntimeException) throwable;
    }
开发者_StackOverflow中文版    if (throwable instanceof Error) {
        throw (Error) throwable;
    }
    try {
        THROW.set((Exception) throwable);
        THROWER.newInstance();
    } catch (final InstantiationException screwed) {
        throw new Error(screwed);
    } catch (final IllegalAccessException screwed) {
        throw new Error(screwed);
    } finally {
        THROW.remove();
    }
}

private final static Class<Impossible> THROWER = Impossible.class;
private final static ThreadLocal<Exception> THROW = new ThreadLocal<Exception>();

static private class Impossible {

    @SuppressWarnings("unused")
    public Impossible() throws Exception {
        throw THROW.get();
    }
}


From Java Puzzlers (puzzle 43):

public static void impossibleThrow(Throwable t)
{
    Thread.currentThread().stop(t); // Deprecated method.
}

The book shows other methods of achieving the same problem, one is a simplified version of yours, the other exploits generic type erasure to throw any Throwable where an Error is expected.


If you want an Exception to bubble up through code not expecting that exception then just wrap it in a RuntimeException

} catch (RuntimeException e) {
   throw e;  // only wrap if needed
} catch (Exception e) {
   throw new RuntimeException("FOO went wrong", e);
}

Remember to let the message be informative. Some day you will have to fix a bug based only on the information in the stack trace.


Wrapping an exception inside a RuntimeException (as suggested by Thorbjørn) is the way to go. However, you usually want to maintain the stacktrace of the original excpetion. Here's how:

  public static void rethrow(final Throwable t)
  {
     if(t instanceof RuntimeException)
        throw (RuntimeException) t;

     RuntimeException e = new RuntimeException(t);
     e.setStackTrace(t.getStackTrace());
     throw e;
  }


I patched javac to remove the error, compiled impossibleThrow(), renamed the source file to something that does not end in .java (which forces the next compile to use the existing .class) and used that.


There is some validity for this question as a debugging tool. Suppose you are working with some code that may have failed and you see that it (perhaps) catches certain exceptions and (perhaps) throws certain exceptions. You suspect that an unexpected exception was not caught. However, the underlying code/system is too complex and the bug is too intermittent to allow you to step through in the debugger. It can be usefull to add the throwing of an exception without changing the method in any other way. In this case, wrapping the exception with a RuntimeException would not work, because you want the calling methods to behave normally.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜