我有两个例外:
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
?
答案 0 :(得分:3)
如果obj1.method()
抛出MyException1
,则可能会抛出MyException1
的非MyException2
子类(或MyException2
的子类)。因此,仅仅声明invokeValidation()
抛出MyException2
。
另一方面,如果您声明invokeValidation() throws MyException1
,那就足够了,因为任何MyException2
例外也是MyException1
。
答案 1 :(得分:2)
我认为如果您使用更有意义的异常名称,您可能会更清楚,因为您的异常命名并不能反映异常的真实目的。
例如,假设您的Exception1
现在是IOException
。它表明存在一些输入输出问题。您的扩展异常现在称为Exception2
,而不是FileNotFoundException
。它表示特定的输入输出错误 - 找不到文件。
因此,正如您所见,FileNotFoundException
是类型的IOException
。这就是extends
定义的关系。
现在想象一下你的方法是否被声明:
public void invokeValidation() throws FileNotFoundException {
obj1.method(); // it throws IOException
obj2.method(); // it throws FileNotfoundException
}
所以,你说"我的方法抛出FileNotFoundException
"。编译器知道如果它遇到这个特殊的Exception,它应该把它扔给调用者。但是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"与超类的关系。它是超类的特定类型。但事实恰恰相反。
答案 2 :(得分:1)
你总是抛出异常及其子类,而不是相反(如果是这种情况,你总是抛出Throwable)。
想象一下MyException2有一个变量:
String name = "whatever";
现在,如果你抛出一个MyException1的实例,但是其他地方捕获了MyException2,那么它就会出错,因为你不能从更特殊的类中向其超类类型转换。 MyException1中没有字段名称。
反过来总是有效,因为MyException2继承了MyException1的所有字段。