Java中的exception和inheritance
假设我们有这个问题
public class Father{ public void method1(){...} } public class Child1 extends Father{ public void method1() throws Exception{ super.method1(); ... } }
Child1
扩展了Father
并覆盖了method1
但是给定了实现, Child1.method1
现在抛出exception。 这不会编译,因为重写方法不能抛出新的exception。
什么是最好的解决方案?
- 将所需的例外传播给
Father
。 对我来说,这是对封装,inheritance和一般OOP(Father
可能抛出永远不会发生的exception)。 - 使用
RuntimeException
代替? 此解决方案不会将Exception
传播给Father
,但Oracle文档和其他来源声明在“客户端代码无法执行任何操作”时应使用exception类。 这不是那种情况,这个exception对于恢复blablabla很有用(为什么使用RuntimeException
导致错误?)。 - 其他..
使用RTE并不是一个坏主意。 这是Spring框架的方法,它工作得很好。 如果您正在实施应用程序可能使用此解决方案
但是,如果您正在实现公开API恕我直言的库,则应使用已检查的exception。 在这种情况下,您应该为示例BaseException
创建自己的exception。 Father
方法method()
将抛出它。 定义ChildException extends BaseException
并声明子类的method1()
以抛出它。
这不会破坏封装:基类抛出基本exception。 它对具体的例外情况一无所知。 Child类抛出具体的exception但是扩展了基本exception,因此可以被客户端代码视为基本exception。
作为一个例子,我可以给你IOException
和扩展它的FileNotFoundException
。 您可以使用输入流捕获IOException
而具体流是FileInputStream
,它会抛出FileNotFoundException
。 但客户不知道这一点。 它捕获IOException
。
如果超类方法没有声明Exception,则子类重写方法不能声明已检查的exception 。 因此,您只能使用未经检查的例外。
其他选项是允许Super类声明ParentException
然后子重写方法可以声明任何ParentException
子类ParentException
取决于什么会引发Child1中的exception。 如果它有一些前提条件等,你可以随时使用RuntimeException的任何子类,例如IllegalArgumentException。
但是,如果存在某种CheckedException,那么逻辑建议您应该处理该方法本身并以其他方式冒泡消息。
我认为一般的经验法则是
如果您知道如何处理它..使用已检查的exception,否则未经检查的exception
“throws”部分是方法签名的一部分。
这就是为什么“child”类的方法不是父类方法的重写。
将所需的exception传播给父..对我来说,这是针对封装,inheritance和一般OOP(父亲可能抛出和永远不会发生的exception)
Au逆转:这是好的 OO。 图像来电者方:
Father f = factory.getSomeImplementation(); f.method1(); // user has no chance to see the `Exception` of Child coming...
工厂可以返回Father
或Child
的例子或像Brother
一样完全不同的东西。 但方法1的合同在所有情况下都必须相同。 此合同包括已检查的例外情况。 这是Liskov替代原则,是OO的基本规则之一。
因此,如果exception是方法1的业务合同的一部分,则必须在根目录中声明。 如果不是(例如一个简单的参数检查),那么RuntimeException
是无论如何都要去的路径(即使没有inheritance)。