Throws 语句不考虑继承的异常

Throws statement doesn't consider inherited exception

我有 2 个例外:

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

如果 obj1.method() 抛出 MyException1,它可能抛出 MyException1 的子 class 而不是 MyException2(或子class,共 MyException2)。因此,仅仅声明 invokeValidation() 抛出 MyException2.

是不够的

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

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

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

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

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

public void invokeValidation() throws FileNotFoundException {

    obj1.method(); // it throws IOException
    obj2.method(); // it throws FileNotfoundException
}

所以,你说 "my method throws a FileNotFoundException"。编译器知道如果它遇到这个特定的异常,它应该将它抛给调用者。但是 obj1 可能会抛出一个 IOException。这可能是一个异常,表明磁盘上没有 space。或者说有坏块。或者文件突然关闭。这可能是很多事情。一个 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"关系。它是一种特定的 超类。但反之则不然。

你总是抛出 Exception 及其子class,而不是相反(如果是这种情况,你总是会抛出 Throwable)。

假设 MyException2 有一个变量:

String name = "whatever";

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

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