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 的所有字段。
我有 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 的所有字段。