在 Java-8 中捕获多个异常

Jok*_*ker 70 java exception try-catch java-8

在尝试多捕获功能时,我在我的m1()方法中发现一切都按预期正常工作。

但是,在m2()相同的代码中不能编译。我刚刚更改了语法以减少代码行数。

public class Main {

    public int m1(boolean bool) {
        try {
            if (bool) {
                throw new Excep1();
            }
            throw new Excep2();
            //This m1() is compiling  abs fine.
        } catch (Excep1 | Excep2 e) {
            return 0;
        }
    }

    public int m2(boolean b) {
        try {
            throw b ? new Excep1() : new Excep2();
            //This one is not compiling.
        } catch (Excep1 | Excep2 e) {
            return 0;
        }
    }

    private static interface I {
    }

    private static class Excep1 extends Exception implements I {
    }

    private static class Excep2 extends Exception implements I {
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么方法不m2()编译?

Era*_*ran 82

表达式的类型

b ? new Excep1() : new Excep2()
Run Code Online (Sandbox Code Playgroud)

is Exception,因为这是Excep1and的共同超类型Excep2

但是,您没有捕获Exception,因此编译器会抱怨它。

如果您 catch Exception,它将通过编译:

public int m2(boolean b) {
    try {
        throw b ? new Excep1() : new Excep2();
    } catch (Exception e) {
        return 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图在您的示例中找到解释条件三元表达式类型的 JLS 条目。

我所能找到的只是这个特定的表达式是15.25.3。参考条件表达式

我不完全确定它算作 poly 表达式还是独立表达式。我认为它是独立的(因为 poly 表达式涉及赋值上下文或调用上下文,我不认为throw语句算作其中任何一个)。

对于独立表达式:“如果第二个和第三个操作数具有相同的类型(可能是 null 类型),那么这就是条件表达式的类型。”

在您的情况下,第二个和第三个操作数具有三种常见类型 - ObjectThrowable并且Exception- 表达式的类型必须是后两种之一,因为“ throw 语句中的表达式必须表示变量或引用类型的值可分配(第 5.2 节)到 Throwable 类型。”

似乎编译器选择了最具体的常见类型 ( Exception),因此 acatch (Exception e)解决了编译错误。

我还尝试用 的两个子类替换您的两个自定义异常IOException,在这种情况下catch (IOException e)解决了编译错误。

  • @Smile 三元条件表达式的类型对于第二个和第三个操作数必须是通用的。因此它不能是“Excep1”或“Excep2”。它只能是“异常”。 (12认同)
  • 15.25.3 中的最后一个要点有答案:“否则,第二个和第三个操作数分别为 S1 和 S2 类型。设 T1 为对 S1 应用装箱转换的结果类型,并设 T2 为结果类型来自将装箱转换应用于 S2。条件表达式的类型是将捕获转换 (§5.1.10) 应用于 lub(T1, T2) 的结果。” lub 这里是最小上界,它是两个表达式类型共享的最接近的公共超类型。 (3认同)

Gid*_*nge 23

你用这一行混淆了编译器:

throw b ? new Excep1() : new Excep2();
Run Code Online (Sandbox Code Playgroud)

编译器看到表达式的结果(在throw的右边)是Except1和Except2之间的公共超类,即Exception,因此你抛出的有效类型变成了Exception。catch 语句无法识别您正在尝试抛出 Excep1 或 Except2。