11

假设我们有这个问题

public class Father{
    public void method1(){...}
}

public class Child1 extends Father{
    public void method1() throws Exception{
    super.method1();
    ... 
    }

}

Child1扩展Father和覆盖method1,但给定的实现Child1.method1现在抛出异常。这不会编译,因为覆盖方法不能抛出新的异常。

什么是最好的解决方案?

  • 将所需的异常传播到Father. 对我来说,这是反对封装、继承和一般 OOP(Father可能会引发永远不会发生的异常)。
  • 使用 aRuntimeException代替?此解决方案不会传播ExceptionFather,但 Oracle 文档和其他来源指出,当“客户端代码无法执行任何操作”时,应使用该类异常。不是这种情况,这个异常对恢复blablabla很有用(为什么改用是错误的RuntimeException?)。
  • 其他..
4

5 回答 5

4

使用 RTE 并不是一个坏主意。这是 Spring 框架的方法论,它工作得很好。如果您正在实施应用程序,可能会使用此解决方案。

但是,如果您正在实现公开 API 恕我直言的库,您应该使用已检查的异常。在这种情况下,您应该创建自己的异常,例如BaseException。方法method()Father抛出它。子类的定义ChildException extends BaseException和声明抛出它。method1()

这不会破坏封装:基类抛出基异常。它对具体的异常一无所知。子类抛出具体异常,但扩展了基本异常,因此客户端代码可以将其视为基本异常。

作为一个例子,我可以给你IOExceptionFileNotFoundException扩展它。您可以IOException在具体流存在FileInputStream并且抛出时使用输入流捕获FileNotFoundException。但客户不知道这一点。它抓住了IOException

于 2012-10-19T16:58:15.350 回答
2

如果超类方法未声明异常,则子类重写方法不能声明已检查异常。所以你只能使用未经检查的异常。

其他选项是允许 Super 类声明ParentException,然后子覆盖方法可以声明任何属于子类的异常ParentException

于 2012-10-19T17:01:13.630 回答
1

取决于在 Child1 中引发异常的原因。如果它有一些先决条件等,您始终可以使用 RuntimeException 的任何子类,例如 IllegalArgumentException。

但是,如果存在某种 CheckedException,那么逻辑建议您应该使用该方法本身来处理它并以其他方式冒泡消息。

我认为一般的经验法则是

如果您知道如何处理它.. 使用已检查的异常,否则使用未检查的异常

于 2012-10-19T16:57:21.230 回答
0

“抛出”部分是方法签名的一部分。
这就是为什么“子”类的方法不是父类方法的覆盖。

于 2012-10-19T16:54:42.183 回答
0

将所需的异常传播给父亲..对我来说,这是反对封装、继承和一般 OOP(父亲可能会抛出和永远不会发生的异常)

Au contraire:这很好OO。对调用方进行映像:

Father f = factory.getSomeImplementation();
f.method1();
// user has no chance to see the `Exception` of Child coming...

工厂可以返回 or 的实例FatherChild完全不同的东西,例如Brother. 但在所有method1情况下,合同必须相同。并且此合同包括已检查的异常。这就是里氏替换原则,是面向对象的基本规则之一。

因此,如果异常是业务合同的一部分,method1 则必须在根处声明。如果不是(例如简单的参数检查),那么RuntimeException无论如何 a 都是要走的路线(即即使没有继承)。

于 2012-10-19T17:05:20.123 回答