【发布时间】:2019-08-02 17:22:13
【问题描述】:
Java 的Proxy 要求从支持InvocationHandler 抛出的任何已检查异常都声明在当前正在调用的接口方法上。
例如,给定一个测试接口,
interface Foo {
void bar1();
void bar2() throws IOException;
}
由始终抛出 IOException 的 InvocationHandler 支持的基于 Proxy 的实例产生两种行为:
-
bar1()将抛出一个未经检查的UndeclaredThrowableException,原因是IOException。 -
bar2()会直接抛出IOException。
现在,使用普通类实现此接口,并从两种方法中抛出IOException¹。任一方法的调用者都会收到直接抛出的IOException。
为什么 Proxy 在运行时强制检查异常,而 VM 的其他部分似乎没有这样做?
注意:这种情况与强制包装已检查异常以便抛出它们的方法明显不同,这在诸如
之类的模式中很常见} catch (e: IOException) {
throw new UncheckedIOException(e);
}
¹ 要么使用“偷偷摸摸”技术,用 Kotlin 等没有检查异常的语言编写它,要么直接在字节码中实现类。
【问题讨论】:
-
我猜这只是设计选择,java 喜欢添加这样奇怪的东西。想法可能是为了防止纯 java 代码在不应该发生的地方得到检查异常 - 因为当时不存在偷偷摸摸的 throw(代理 API 是在泛型存在之前创建的),并且其他编译器和手动字节码操作不是什么这也是意料之中的。 (仪器后来也加了)
-
我不完全确定答案会是什么样子。但是导致
UndeclaredThrowableException被抛出的代码一般是根据声明的 异常生成的。只有被声明的才会被正常接收。那些 not 声明的将被视为“any throwable”,作为最后的手段被捕获和包装。相关代码是例如在github.com/JetBrains/jdk8u_jdk/blob/master/src/share/classes/… -
您的脚注证明了您所引用的技术在任何一种情况下都不受基本语言的支持。当然,任何偷偷摸摸的技术都会偷偷溜过去。不清楚您在这里真正要问的是什么。
-
@user207421 语言选择无关紧要。我可以重写由字节码构成的问题,并且不需要脚注。这是虚拟机的行为。
标签: java reflection