在Java-8中捕获多个异常


71

在尝试多捕获功能时,我在自己的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 {
    }
}

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


22
您遇到什么编译错误?
加文

Answers:


79

表达式的类型

b ? new Excep1() : new Excep2()

Exception的,因为这是共同的超类型Excep1Excep2

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

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

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

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

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

我不完全确定它是作为多边形表达式还是独立表达式。我认为它是独立的(因为多边形表达式包含一个赋值上下文或一个调用上下文,并且我认为throw语句不算这两者)。

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

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

看来编译器选择了最特定的通用类型(Exception),因此a catch (Exception e)解决了编译错误。

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


11
@Smile三元条件表达式的类型对于第二个和第三个操作数必须是公共的。因此,它不能为Excep1Excep2。它只能是Exception
伊兰

2
15.25.3中的最后一个项目符号点具有答案:“否则,第二个和第三个操作数分别是S1和S2类型。设T1为对Box进行装箱转换得到的类型,而T2为产生的装箱类型。 “条件表达式的类型是将捕获转换(§5.1.10)应用于lub(T1,T2)的结果。” lub这里是Least Upper Bound,这是两个表达式的类型共享的最接近的普通超类型。
amalloy

22

您将编译器与此行混淆:

throw b ? new Excep1() : new Excep2();

编译器看到表达式的结果(在throw的左边)是Except1和Except2之间的公共超类,它是Exception,因此您要抛出的有效类型将变为Exception。catch语句无法识别您要抛出Excep1或Except2。


4

Java限制您捕获或声明该方法可能引发的所有异常类型,

它会搜索两个(/全部)异常的公共父对象,并期望您将其捕获或声明为抛出,例如,如果Excep1扩展,则Throwable您还必须捕获Throwable

在第一种情况下,Java确保您要么抛出Excep1要么Excep2

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.