Why is it legal to re-throw a Throwable in certain cases, without declaring it?
我希望以下代码在
1 2 3 4 5 6 7 8 9 10 11 | public class Test { public static void main(String[] args) { try { throw new NullPointerException(); } catch(Throwable t) { System.out.println("Caught"+t); throw t; } } } |
如果将
不会按预期方式编译:
1 2 3 4 5 6 7 8 9 10 11 12 | public class Test { public static void main(String[] args) { try { throw new NullPointerException(); } catch(Throwable t) { Throwable t2 = t; System.out.println("Caught"+t2); throw t2; } } } |
这样编译:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class Test { public static void main(String[] args) { try { throwsRuntimeException(); } catch(Throwable t) { System.out.println("Caught"+t); throw t; } } public static void throwsRuntimeException() { throw new NullPointerException(); } } |
这不是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class Test { public static void main(String[] args) { try { throwsCheckedException(); } catch(Throwable t) { System.out.println("Caught"+t); throw t; } } public static void throwsCheckedException() { throw new java.io.IOException(); } } |
这也可以编译:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class Test { public static void main(String[] args) throws java.io.IOException { try { throwsIOException(); } catch(Throwable t) { System.out.println("Caught"+t); throw t; } } public static void throwsIOException() throws java.io.IOException { throw new java.io.IOException(); } } |
一个更复杂的示例-被检查的异常由外部catch块捕获,而不是被声明为抛出。 这样编译:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class Test { public static void main(String[] args) { try { try { throwsIOException(); } catch(Throwable t) { System.out.println("Caught"+t); throw t; } } catch(java.io.IOException e) { System.out.println("Caught IOException (outer block)"); } } public static void throwsIOException() throws java.io.IOException { throw new java.io.IOException(); } } |
因此,当编译器可以确定捕获的异常始终合法地重新抛出时,似乎有一种特殊情况允许重新抛出异常。 它是否正确? JLS在哪里指定? 还有其他类似的难解之类的案例吗?
JLS 11.2.2(重点是我)对此进行了介绍:
A throw statement whose thrown expression is a final or effectively final exception parameter of a catch clause C can throw an exception class E iff:
E is an exception class that the try block of the try statement which declares C can throw; and
E is assignment compatible with any of C's catchable exception classes; and
(...)
换句话说,文档中引用的类型
这就是为什么要竭尽全力说出最终或有效的最终异常参数的原因-如果重新分配了示例中的
因为编译器足够聪明,所以知道不能从try块中抛出已检查的异常,因此捕获的Throwable不是必须声明的已检查的异常。
请注意,如果我没有记错的话,从Java 7开始就是如此。
当捕获