Can someone explain this code?
public class SneakyThrow {
public static void sneakyThrow(Throwable ex) {
SneakyThrow.<RuntimeException>sneakyThrowInner(ex);
}
private static <T extends Throwable> T sneakyThrowInner(Throwable ex) throws T {
throw (T) ex;
}
public static void main(String[] args) {
SneakyThrow.sneakyThrow(new Exception());
}
}
It may seems strange, but this doesn't produce a cast exception, and permits to throw a checked exception without having to declare it in the signature, or to wrap it in an unchecked exception.
Notice that neither sneakyThrow(...)
or the main are declaring any checked exception, but the output is:
Exception in thread "main" java.lang.Exception
at com.xxx.SneakyThrow.main(SneakyThrow.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
This hack is used in Lombok, with the annotation @SneakyThrow, which permits to throw checked exceptions without declaring them.
I know it has something to do with type erasure, but i'm not sure to understand every part of the hack.
Edit:
I know that we can insert an Integer
in a List<String>
and that checked/unchecked exceptions distinction is a compile time feature.
When casting from a non-generic type like List
to a generic type like List<XXX>
the compiler produces a warning. But it's less common to cast to a generic type directly like (T) ex
in the above code.
If you want, the part that seems strange for me is that I understand that inside the JVM a List<Dog>
and List<Cat>
looks the same, but the above code seems to mean that finally we can also assign a value of type Cat to a variable of type Dog or something like that.