【问题标题】:Throws statement doesn't consider inherited exceptionthrows 语句不考虑继承的异常
【发布时间】:2015-04-07 19:23:41
【问题描述】:

我有两个例外:

class MyException1 extends Exception {
 --
}

class MyException2 extends MyException1 {
--
}


function invokeValidation() throws MyException2 {

    obj1.method() // it throws MyException1
    obj2.method() // it throws MyException2
}

上面的代码说unhandled exception type MyException1, 即使MyException2 扩展了MyException1。为什么它在 throws 语句中期望 MyException1

【问题讨论】:

    标签: java exception-handling throws checked-exceptions


    【解决方案1】:

    如果obj1.method() 抛出MyException1,它可能会抛出不是MyException2MyException1 的子类(或MyException2 的子类)。因此,仅声明 invokeValidation() 抛出 MyException2 是不够的。

    另一方面,如果您声明invokeValidation() throws MyException1,这就足够了,因为任何MyException2 异常也是MyException1

    【讨论】:

    • 值得注意的是,说throws MyException1就足够了。
    • @MadConan,@Eran 感谢您的回复
    【解决方案2】:

    我认为,如果您使用更有意义的异常名称,您可能会更清楚,因为您的异常命名并不能反映异常的真正目的。

    例如,假设您的 Exception1 现在是 IOException。这表明存在一些输入输出问题。并且您的扩展异常,而不是 Exception2 现在称为 FileNotFoundException。它表示特定的输入输出错误 - 找不到文件。

    所以,如您所见,FileNotFoundException 是一种 IOException。这就是 extends 这个词所定义的关系。

    现在想象一下,如果你的方法被声明了:

    public void invokeValidation() throws FileNotFoundException {
    
        obj1.method(); // it throws IOException
        obj2.method(); // it throws FileNotfoundException
    }
    

    所以,你说“我的方法抛出一个FileNotFoundException”。编译器知道如果它遇到这个特定的异常,它应该把它扔给调用者。但是obj1 可能会抛出IOException。这可能是一个异常,表明磁盘上没有空间。或者说有坏块。或者文件被突然关闭。这可能是很多事情。 IOException不是FileNotFoundException。因此,编译器与它没有任何关系,它告诉你这是一个未处理的异常。

    但是如果你的方法被声明了:

    public void invokeValidation() throws IOException {
    
        obj1.method(); // it throws IOException
        obj2.method(); // it throws FileNotfoundException
    }
    

    编译器不会抱怨。为什么?因为对于obj1,它会抛出一个IOException,这很好,它就在标题中,可以向上抛出一个级别。而对于obj2,它知道FileNotFoundException 是一个(类型)IOException,因此它被允许抛出它。它与IOException 是多态的,调用者会知道如何处理它。

    所以继承的层次很重要。如果你有两个方法抛出两个异常,一个是另一个的超类,你应该声明你的方法抛出超类。因为任何子类与超类都有“is_A”关系。它是超类的一种特定。但反之则不然。

    【讨论】:

      【解决方案3】:

      你总是抛出异常及其子类,而不是相反(如果是这样的话,你总是抛出 Throwable)。

      想象一下 MyException2 有一个变量:

      String name = "whatever";
      

      现在如果你抛出一个 MyException1 的实例,但在其他地方捕获 MyException2,它会出错,因为你不能从更特殊的类类型转换到它的超类。 MyException1 中不存在该字段名称。

      反之亦然,因为 MyException2 继承了 MyException1 的所有字段。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多