Java无法访问的catch块编译器错误

为什么在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 } } } 

有任何想法吗?

一个RuntimeException可能会被任何代码抛出。 换句话说,编译器不能轻易预测哪种代码可以抛出它。 一个RuntimeException可以被catch(Exception e)catch(Exception e)

然而, IOException是一个检查exception – 声明为抛出它的唯一方法调用可以这样做。 编译器可以(合理地)确信它不可能发生,除非有方法调用被声明为抛出它。

Java编译器根本不考虑“在try块内根本没有任何代码”的情况 – 它总是允许你捕获未经检查的exception,因为在所有合理的情况下都会有可能抛出未经检查的exception的代码。

从JLS 第14.21节 :

如果满足以下两个条件,则catch块C是可达的:

  • try块中的某些expression式或throw语句是可访问的,并且可以抛出exception,该exception的types可分配给catch子句C的参数。(如果包含它的最内层语句可到达,则expression式被视为可访问)。
  • 在try语句中没有早先的catch块A,使得C的参数types与A的参数types相同或是其types的子类。

可以说编译器应该认识到,在你的第一种情况下,在try块中没有任何expression式……看起来对于我来说这仍然是一个不可达的catch子句。

编辑:如注释中所述, 第14.20节包含这一点:

如果catch子句捕获检查的exceptiontypesE1,但是不存在检查的exceptiontypesE2 ,则以下所有条件都成立,这是编译时错误:

  • E2 <: E1
  • catch子句对应的try块可以抛出E2
  • 紧接着的try语句的前面的catch块没有捕获E2E2的超types。

除非E1是exception类。

所以看起来这就是你实际上所犯的错误,但是规范并不像14.21中的无法达到的抓钩那样清晰。

IOexception只能在编译器预测可能会引发IOExceptionexception的代码中被捕获。 所以你得到一个警告,IOexception永远不会从try语句体中抛出(因为try体内没有任何东西)。

你不能捕获未经检查的exception,因为它们不能被抛出。 您可以捕获Exception因为未经检查的运行时exception是一个Exception ,可能会被抛出。

因为对于被检查的exception,引发它们的方法必须通过'throws'关键字来明确地陈述这个事实,因此如果一个块在你的情况下没有'抛出IOException',编译器就有了这个信息,被抛出,所以无论你在捕捉之后做什么,都是无法达到的。

IOException是仅与IO相关的代码抛出的checkedexception。 由于你的try块什么也不做,IO相关的事情都不会发生,IOExceptions永远不会被抛出,所以catch块永远不会被执行,编译器也不会让你绕过它。 正如你所说,exception可能是指任何时候都可能发生的未经检查的运行时exception。 这是未经检查和已检查exception之间的主要区别,这就是为什么编译器不强制执行代码来捕获每个可能的运行时exception。

简单的Java假设任何代码行可以抛出一个通用的ExceptionThrowable ,即。 OutOfMemoryException ,这是一个Error而不是一个Exception 。 同样适用于NPE。

IOException是只能由托pipe代码引发的特定exception,所以如果在catch块中没有I / O调用,那么编译器就没有机会去捕获它。

只是为了与C#世界进行比较,在C#中这样的代码将被编译,但是会是一个概念性的错误,因为如果你没有做任何事情,你不会到达catch块。 像ReSharper这样的工具可以提醒你。