关于LSP原则中父子类方法抛出异常的变化与后置条件变化的关系的理解

本文深入探讨了里氏替换原则(LSP)在异常处理中的应用,解释了为何子类重写父类方法时不能随意增加异常抛出。分析了子类可以抛出父类已声明异常的一部分或其子类的情况,并通过实例说明如何保持后置条件的强弱一致性,遵循LSP原则。总结了异常处理与责任推卸的关系,强调了合理设计异常处理对于维持软件设计稳定性和客户端使用便利性的重要性。
摘要由CSDN通过智能技术生成

LSP原则:任何基类可以出现的地方,子类一定可以用子类替换。

提出问题:当一个子类重写父类方法时,如果该父类方法throws了一种或多种异常,那么子类在重写这个方法的时候可以做哪些改变呢?

一、如何理解抛出异常相当于后置条件变弱

这里的异常一般都针对checked异常。对于unchecked异常,方法一般都不做处理,只需要它在发生异常的时候被抛出即可。

首先需要明白一个最基本的例子:如果父类方法没有抛出异常,那么子类方法重写时就不可以抛出异常。(指在方法签名后throws异常)

那么我们先来理解这个问题:父类没有throws异常意味着什么?意味着它需要处理这些异常,需要用try/catch对异常进行捕捉和处理。而如果子类在重写该方法的时候加上了throws关键字意味着什么?意味着它要把处理这些异常的责任推卸给调用者,而它的方法内部就不需要try/catch来进行捕捉和处理。

这显然时不符合LSP原则的,因为在之前调用父类方法的位置,如果将其替换为子类方法,那你这个新的子类方法抛出的异常就没被处理,事实上编译器是不会允许你这么干的。

所以强弱关系就很清楚了:之前你父类需要把这些异常都处理掉,而你子类要是加了throws之后就可以不处理这些异常了。显然,后置条件变弱了!

站在客户端的角度就是,之前我调用你这个方法不需要管你内部有什么异常,拿来就可以直接用。而现在你要是加了throws之后,我再调用你那我就必须考虑这些异常,针对这些异常作相应的处理,这显然增大了客户端的难度。

二、父类抛出的异常和子类抛出的异常是什么关系?

先说结论:子类方法抛出的异常可以是父类方法throws关键字后面的那些异常中的一部分。或者,子类抛出的异常是父类异常的子类。

如何理解呢?

eg1. 子类方法抛出的异常是父类方法抛出异常的一部分

public class Basic {
    public void b() throws IOException,RuntimeException {}

}

public class Son extends Basic {
    @Override
    public void b() throws IOException {}
}

Son是Basic的子类,它重写父类b()方法的时候,将throws后面改为了IOException,这只是父类方法抛出异常的一部分。

这样做为什么可以呢?按照第一部分的思路就可以想清楚,父类之前有这么多异常都不用处理,而子类现在只选择了其中一部分不做处理,剩下的那些它都处理了。这就是子类方法的后置条件增强了,所以是符合LSP原则的。

eg2.子类方法抛出的异常是父类方法抛出异常的子类

public class Basic {
    public void b() throws Throwable {}

}

public class Son extends Basic {
    @Override
    public void b() throws IOException {}
}

父类中抛出的是Throwable类型,而子类抛出的是IOException。根据异常的继承层次可以知道,IOException所示Throwable的子类。

那么这么做为什么可以呢?还是按照第一部分的思路,父类之前抛出的异常是一大类异常,而子类现在只抛出了其中的一个子类。显然子类需要处理更多的异常,所以后置条件增强满足LSP原则。

三、总结

 综上可以看出,抛出异常其实就相当于一种推卸责任。所以抛出的异常越多、抛出的异常范围越大,那么你的后置条件就是越弱的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值