捕获非本地抛出的异常?

9
我的问题与try catch块的句法行为有关。
空的try块和一个如下的catch块。
void fun() {
    try {}
    catch(Exception e) {}
}

或者

try {}
catch(ArrayIndexOutOfBoundsException e) {}

代码编译成功,但编译器报错:

try {}
catch(IOException e) {}

为什么编译器允许捕获任何类型的Exception或RuntimeException,而对于已检查异常的不可达代码则会报错?这是因为JVM代码可以抛出这些类型吗?JVM如何在空的try块中抛出ArrayIndexOutOfBoundsException呢?
1个回答

11

空块是一个特殊情况,JLS并没有特别处理。JLS要求的是,如果你捕获了一个已检查异常,那么try块中的代码必须能够抛出该异常(即直接抛出或调用可能抛出它的方法)。

换句话说,对于已检查的异常,有一个特定的合理性检查,但并不适用于所有异常。

这在JLS 14.21中有描述,具体如下:

如果某个语句无法执行,因为它是不可达的,则会产生编译时错误。
一个异常捕获块C是可到达的当且仅当以下两个条件均为真:
1. 要么C的参数类型是未经检查的异常类型或Exception或Exception的超类,或者在try块中的某个表达式或throw语句是可到达的并且可以抛出一个其类型可分配给C的参数类型的已检查异常。(当且仅当它所在的最内层语句是可到达的时,表达式是可到达的。)参见§15.6有关表达式的正常完成和突然完成的内容。
2. 在try语句中没有早期的catch块A,该catch块的参数类型与C的参数类型相同或是其子类。
强调添加:它显示,如果您捕获了未经检查的异常类型,则可以到达catch块。
我个人觉得措辞有点混乱。稍微改一下措辞,第一个要点只是说捕获子句必须捕获以下之一:
  • 未经检查的异常
  • 异常
  • Throwable(除了Object之外,它是Exception的唯一超类,您无法捕获)
  • 可以由try块抛出的已检查异常

第二个项目防止catch块因先前try中的catch而变得无法访问。例如:

try {
    whatever();
} catch (Exception e) {
    handleException(e);
} catch (NullPointerException e) {
    // This block is unreachable, because a NullPointerException is an
    // Exception and will thus be handled by the previous catch block.
    handleNpe(e);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接