I am trying to understand how the @SneakyThrows
annotation in Lombok actually works under the hood.
From this SO answer, I can gather it uses the method Lombok.sneakyThrows()
under the hood.
The code for Lombok.sneakyThrows() is as follows:
public static RuntimeException sneakyThrow(Throwable t) {
if (t == null) throw new NullPointerException("t");
return Lombok.<RuntimeException>sneakyThrow0(t);
}
@SuppressWarnings("unchecked")
private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T {
throw (T)t;
}
From what I can make out is that all it is doing is casting it to a java.lang.RuntimeException
so the compiler does not complain.
But shouldn't that technically give a ClassCastException
?
For example:
public static void main(String args[]) {
Throwable i = new InterruptedException();
RuntimeException rr = (RuntimeException) i;
}
The above code results in a ClassCastException.
Then why does the same thing not happen in case of Lombok?
Notice this is not a cast to RuntimeException
, but a cast to a generic parameter T
, constrained to Throwable
. Because of Type Erasure, this cast cannot be checked. The cast is a completely unchecked cast.
The runtime doesn't know what T
is, except that it extends Throwable
. So it can't check whether t
actually is a T
, and throw an exception if it is not. All it can do is check if t
is Throwable
, but t
's type is already Throwable
, so there's no need to do that either.
Normally, you would see a warning about this unchecked cast, and that is what @SuppressWarnings("unchecked")
is suppressing.