最后投掷和抛出的区别

时间:2017-12-08 10:27:29

标签: java

我正在准备 OCP 考试,我正在使用 Enthuware 。 我有这个问题,编译和运行以下代码的结果是什么?

try {
    throw new IOException();
} catch(IOException e) {
    throw e;
} finally {
    throw new RuntimeException();
}

显然,代码确实编译但是抛出RuntimeException并且我完全理解为什么。 我只是好奇为什么以下代码无法编译:

try {
    throw new IOException();
} catch(IOException e) {
    throw e;
} finally {
    test();
}

test()函数的位置如下:

static final void test() throws RuntimeException {
    throw new RuntimeException();
}

即使我将test函数声明为final,因为我认为编译器可能知道覆盖 ......

有人可以向我解释一下吗?

抱歉英文不好!

- 修改 只是想知道为什么要投票?

错误消息是编译错误:

  

未处理的异常类型IOException

我尝试编译时的错误消息是:

  

线程“main”中的异常java.lang.Error:未解决的编译问题:       未处理的异常类型IOException

2 个答案:

答案 0 :(得分:0)

第一个代码段编译是因为finally块在返回值之前运行,或者从方法的非finally部分抛出异常。您投掷RuntimeException这一事实意味着您不会投掷您原本应该的IOException。编译器可以解决这个问题,因此它并不坚持要么声明或捕获IOException

但编译器只在执行此检查时一次查看一个方法。因此第二个代码段无法编译,因为编译器不会检查test() 总是 抛出RuntimeException。相反,它假定test()可能抛出RuntimeException;如果发生这种情况,IOException将被抛出。因此,编译器坚持要么捕获IOException,要么在throws子句中声明它。

答案 1 :(得分:0)

在java中,异常处理具有概念异常传播。

首先从堆栈顶部抛出异常,如果没有捕获,则将调用堆栈下拉到前一个方法,如果没有捕获,则异常再次下降到前一个方法,依此类推直到它们被捕获或直到它们到达调用堆栈的最底部。这称为异常传播。

规则1:默认情况下,未经检查的例外情况会在主叫链中传播(传播)。

规则2:默认情况下,Checked Exceptions不会在调用链中转发(传播)。

try {
    throw new IOException();
} catch(IOException e) {
    throw e;
} finally {
    throw new RuntimeException();
}

在上面的代码片段中,抛出RuntimeException以防止抛出IOException。

try {
    throw new IOException();
} catch(IOException e) {
    throw e;
} finally {
    test();
}
static final void test() throws RuntimeException {
    throw new RuntimeException();
}

在上面的代码片段test()方法中抛出RuntimeException但不会阻止抛出IOException。 正如规则2 默认情况下,编译器不会传播Checked Exceptions,因此您必须声明或处理异常。

让我们举例说明如果用 RuntimeException 替换 IOException ,那么它就不会给出编译时错误,因为默认情况下规则1 未经检查异常被转发在调用链(传播)。

try {
    throw new RuntimeException();
} catch(RuntimeException e) {
    throw e;
} finally {
    test();
}
static final void test() throws RuntimeException{
    throw new RuntimeException();
}