Java SneakyThrow抛出异常,类型擦除
有人可以解释此代码吗?
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());
}
}
看起来似乎很奇怪,但这不会产生强制转换异常,并允许抛出已检查的异常而不必在签名中声明它或将其包装在未检查的异常中。
注意,sneakyThrow(...)
或者main都没有声明任何检查过的异常,但是输出是:
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)
在Lombok中使用此hack,带有@SneakyThrow批注,该批注允许抛出已检查的异常而无需声明它们。
我知道它与类型擦除有关,但是我不确定要了解hack的每个部分。
我知道我们可以在中插入Integer
,List<String>
并且选中/未选中的异常区别是编译时功能。
当从非通用类型List
转换为通用类型时List<XXX>
,编译器会产生警告。但是直接像(T)
ex上面的代码中那样直接转换为泛型类型的情况并不常见。
如果您愿意,对我来说很奇怪的部分是,我了解JVM
a内的内容,List<Dog>
并且List<Cat>
看起来相同,但是上面的代码似乎意味着最终我们也可以将Cat类型的值分配给Dog类型的变量或这样的事情。
回答:
如果使用它进行编译,-Xlint
则会收到警告:
c:\Users\Jon\Test>javac -Xlint SneakyThrow.javaSneakyThrow.java:9: warning: [unchecked] unchecked cast
throw (T) ex;
^
required: T
found: Throwable
where T is a type-variable:
T extends Throwable declared in method <T>sneakyThrowInner(Throwable)
1 warning
基本上是说“ 在执行时并没有 真正 检查这个强制转换”(由于类型擦除)-因此编译器无奈地假设您做的是正确的,知道它实际上不会被检查。
现在只有 编译器 关心已检查和未检查的异常-它根本不是JVM的一部分。因此,一旦您通过了编译器,就可以自由上班了。
我强烈建议您避免这样做。
在许多情况下,使用泛型时会进行“真实”检查,因为某些东西使用了所需的类型-但这并非 总是 如此。例如:
List<String> strings = new ArrayList<String>();List raw = strings;
raw.add(new Object()); // Haha! I've put a non-String in a List<String>!
Object x = strings.get(0); // This doesn't need a cast, so no exception...
以上是 Java SneakyThrow抛出异常,类型擦除 的全部内容, 来源链接: utcz.com/qa/427383.html