Search code examples
javagenericsexceptionlombokchecked-exceptions

Why doesn't Lombok.sneakyThrows throw a ClassCastException?


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?


Solution

  • 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.