Java不可达catch块编译器错误

bar*_*ary 16 java scjp

为什么在Java中我们可以捕获一个Exception即使它没有被抛出,但我们无法捕获它的子类(除了"unchecked" RuntimeException和它的子类).示例代码:

class Test {
    public static void main(String[] args) {
        try {
            // do nothing
        } catch (Exception e) {
            // OK           
        }

        try {
            // do nothing
        } catch (IOException e) {
               // COMPILER ERROR: Unreachable catch block for IOException.
               //This exception is never thrown from the try statement body
        }       
    }
}
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Jon*_*eet 25

任何代码RuntimeException都可以抛出A. 换句话说,编译器无法轻易预测可以抛出哪种代码.A 可以被一个块抓住.RuntimeExceptioncatch(Exception e)

IOException但是,是一个经过检查的异常 - 只有声明抛出它的方法调用才能这样做.除非有声明抛出它的方法调用,否则编译器可以(合理地)确信它不可能发生.

Java编译器根本不考虑"有一个在所有的try块中无码"的情况-它总是让你赶上unchecked异常,在所有合理的情况下会出现代码,可以潜在地抛出一个未经检查的异常.

从JLS 第14.21节:

如果满足以下两个条件,则可以访问catch块C:

  • try块中的某些表达式或throw语句是可以访问的,并且可以抛出一个异常,其类型可以赋予catch子句C的参数.(如果包含它的最内层语句可以访问,则表达式被认为是可到达的.)
  • try语句中没有先前的catch块,因此C的参数类型与A参数类型的子类相同.

可以说编译器应该意识到在你的第一种情况下try块中没有表达式......看起来这对我来说仍然是一个无法访问的catch子句.

编辑:如评论中所述,第14.20节包含:

如果catch子句捕获已检查的异常类型E1,但是没有检查的异常类型E2,以便以下所有内容成立,则为编译时错误:

  • E2 <:E1
  • try对应于该catch子句的块可以抛出E2
  • 前面没有catch立即封闭try语句块捕获E2或的超E2.

除非E1是类Exception.

所以看起来这就是你实际上在犯规的情况,但规格并不像14.21中无法到达的陷阱那么清晰.


Mav*_*eňツ 5

只有在编译器预测代码中可能存在抛出IOException的内容时,才能捕获IO异常.因此,您将收到一条警告,即IO异常永远不会从try语句体中抛出(因为try的正文中没有任何内容).