Yes, there is a way to write a method that will avoid wrapping your checked exceptions. For this use case it is a perfect match, although you should definitely be very careful with it, since it can easily confuse the uninitiated. Here it is:
@SuppressWarnings("unchecked")
public static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
throw (T) t;
}
and you'd use it as
catch (Throwable t) { sneakyThrow(t); }
As commented by Joachim Sauer, in certain cases it helps convince the compiler that the line calling sneakyThrow
causes the method to terminate. We can just change the declared return type:
@SuppressWarnings("unchecked")
public static <T extends Throwable> T sneakyThrow(Throwable t) throws T {
throw (T) t;
}
and use it like this:
catch (Throwable t) { throw sneakyThrow(t); }
For educational purposes it is nice to see what's going on at the bytecode level. The relevant snippet from javap -verbose UncheckedThrower
:
public static <T extends java.lang.Throwable> java.lang.RuntimeException sneakyThrow(java.lang.Throwable) throws T;
descriptor: (Ljava/lang/Throwable;)Ljava/lang/RuntimeException;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: athrow
Exceptions:
throws java.lang.Throwable
Signature: #13 // <T:Ljava/lang/Throwable;>(Ljava/lang/Throwable;)Ljava/lang/RuntimeException;^TT;
Note there is no checkcast
instruction. The method even legitimately declares to throw T
, which can be any Throwable
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…