JLS 的哪些部分证明能够抛出已检查的异常,就好像它们未被选中一样?
我最近发现并在博客上写道,可以通过javac编译器偷偷出现一个经过检查的异常,并将其扔到不能扔掉的地方。这将在 Java 6 和 7 中编译和运行,并抛出一个 without 或 子句:SQLException
throws
catch
public class Test {
// No throws clause here
public static void main(String[] args) {
doThrow(new SQLException());
}
static void doThrow(Exception e) {
Test.<RuntimeException> doThrow0(e);
}
static <E extends Exception> void doThrow0(Exception e) throws E {
throw (E) e;
}
}
生成的字节码表示 JVM 并不真正关心选中/未选中的异常:
// Method descriptor #22 (Ljava/lang/Exception;)V
// Stack: 1, Locals: 1
static void doThrow(java.lang.Exception e);
0 aload_0 [e]
1 invokestatic Test.doThrow0(java.lang.Exception) : void [25]
4 return
Line numbers:
[pc: 0, line: 11]
[pc: 4, line: 12]
Local variable table:
[pc: 0, pc: 5] local: e index: 0 type: java.lang.Exception
// Method descriptor #22 (Ljava/lang/Exception;)V
// Signature: <E:Ljava/lang/Exception;>(Ljava/lang/Exception;)V^TE;
// Stack: 1, Locals: 1
static void doThrow0(java.lang.Exception e) throws java.lang.Exception;
0 aload_0 [e]
1 athrow
Line numbers:
[pc: 0, line: 16]
Local variable table:
[pc: 0, pc: 2] local: e index: 0 type: java.lang.Exception
JVM接受这一点是一回事。但是我有一些怀疑Java语言是否应该这样做。JLS的哪些部分证明了这种行为的合理性?这是一个错误吗?还是Java语言的一个隐藏得很好的“功能”?
我的感受是:
-
doThrow0()
的 绑定到 中。因此,在 中不需要与 JLS §11.2 类似的子句。<E>
RuntimeException
doThrow()
throws
doThrow()
-
RuntimeException
与 赋值兼容,因此编译器不会生成强制转换(这将导致 )。Exception
ClassCastException