在 Java-8 中捕获多个异常

2022-08-31 14:11:12

在尝试我在方法中发现的多捕获功能时,一切都按预期工作正常。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()


答案 1

表达式的类型

b ? new Excep1() : new Excep2()

是 ,因为这是 和 的常见超类型。ExceptionExcep1Excep2

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

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

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

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

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

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

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

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

编译器似乎选择了最具体的通用类型 (),因此 a 解决了编译错误。Exceptioncatch (Exception e)

我还尝试将两个自定义异常替换为 的两个子类,在这种情况下,可以解决编译错误。IOExceptioncatch (IOException e)


答案 2

您将编译器与此行混淆:

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

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