在 Java-8 中捕获多个异常

Posted

技术标签:

【中文标题】在 Java-8 中捕获多个异常【英文标题】:Catching multiple exceptions in Java-8 【发布时间】:2020-04-26 23:32:49 【问题描述】:

在尝试我在 m1() 方法中发现的 multi-catch 功能时,一切正常。

但是,在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()

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. Reference Conditional Expression。

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

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

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

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

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

【讨论】:

@Smile 三元条件表达式的类型必须为第二个和第三个操作数所共有。因此它不能是Excep1Excep2。只能是Exception 15.25.3 中的最后一个要点有答案:“否则,第二个和第三个操作数分别为 S1 和 S2 类型。令 T1 为对 S1 应用装箱转换后的类型,并令 T2 为将装箱转换应用于 S2 的类型。条件表达式的类型是将捕获转换 (§5.1.10) 应用于 lub(T1, T2) 的结果。这里的 lub 是 Least Upper Bound,这是两个表达式的类型共享的最接近的公共超类型。【参考方案2】:

您将编译器与这一行混淆了:

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

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

【讨论】:

【参考方案3】:

Java 限制您捕获或声明该方法可以抛出的所有异常类型,

它为两个 (/all) 异常搜索公共父级,并期望您捕获或声明为 throws,例如,如果 Excep1 扩展 Throwable 您还必须捕获 Throwable

在第一种情况下,Java 确定您正在抛出 Excep1Excep2

【讨论】:

以上是关于在 Java-8 中捕获多个异常的主要内容,如果未能解决你的问题,请参考以下文章

在 oracle 中一次捕获多个异常

捕获多个自定义异常? - C++

我可以在同一个 catch 子句中捕获多个 Java 异常吗?

python常见异常和异常捕获

Java中多个异常的捕获顺序(多个catch)

Java方法中捕获多个异常的处理机制