1

我有两个例外:

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,即使MyException2extends MyException1。为什么它期望MyException1在 throws 语句中?

4

3 回答 3

4

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

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

于 2015-04-07T19:25:37.307 回答
2

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

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

所以,如您所见, aFileNotFoundException 一种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
}

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

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

于 2015-04-07T19:38:41.710 回答
1

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

想象一下 MyException2 有一个变量:

String name = "whatever";

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

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

于 2015-04-07T19:40:11.050 回答