这是怎么回事?
为什么IOException(RemoteException)的受检查子级被转换为RuntimeException?
摘录自here
import java.rmi.RemoteException;
class Thrower {
public static void spit(final Throwable exception) {
class EvilThrower<T extends Throwable> {
@SuppressWarnings("unchecked")
private void sneakyThrow(Throwable exception) throws T {
throw (T) exception; // something interesting
}
}
new EvilThrower<RuntimeException>().sneakyThrow(exception);
}
}
public class ThrowerSample {
public static void main( String[] args ) {
Thrower.spit(new RemoteException("go unchecked!"));
}
}
答案 0 :(得分:3)
这是怎么回事?
此代码规避了Compile-Time Checking of Exceptions。
使用使用已检查异常的api并不总是很方便。
最著名的例子之一是JDBC。使用jdbc总是需要开发人员处理SQLException
。但是通常您不知道应该如何处理该异常。
或者,如果您正在使用的库中,开发人员决定从Exception
而不是RuntimeException
继承其异常。
IOException
(RemoteException
)的选中子转换为RuntimeException
?它不会转换为RuntimeException
。
引发的异常为RemoteException
:
Exception in thread "main" java.rmi.RemoteException: go unchecked!
该代码段使用Java泛型“技巧”。如果没有@SuppressWarnings("unchecked")
行,编译器将生成未经检查的强制转换警告。
该代码段是Java Puzzlers: Traps, Pitfalls, and Corner Cases的第43个难题的解决方案之一:
// Don’t do this - circumvents exception checking!
public static void sneakyThrow(Throwable t) {
Thread.currentThread().stop(t); // Deprecated!!
}
可以编写在功能上等效于
sneakyThrow
的方法 而不使用任何不推荐使用的方法。实际上,至少有两种方法可以做到这一点。 其中之一仅在5.0版及更高版本中有效。你能写这样的 方法?它必须用Java而不是JVM字节码编写。您不得更改 客户端编译后的方法。您的方法不一定是完美的: 如果不能抛出Exception
的一两个子类,则可以接受。
本书中使用泛型的解决方案:
// Don’t do this either - circumvents exception checking!
class TigerThrower<T extends Throwable> {
public static void sneakyThrow(Throwable t) {
new TigerThrower<Error>().sneakyThrow2(t);
}
private void sneakyThrow2(Throwable t) throws T {
throw (T) t;
}
}
关于本书中此解决方案的说明:
警告是编译器告诉您可能正在开枪的方式 在脚上,事实上你是。未经检查的强制转换警告会告诉您 有问题的演员表不会在运行时检查。当您不受检查时 发出警告,修改程序以消除它,或者说服自己 演员不能失败
总而言之,虚拟机未强制执行Java的异常检查 机。它是一种编译时工具,旨在使编写正确的代码更容易 程序,但可以在运行时规避。为了减少曝光,请勿 忽略编译器警告。