锁定老帖子 主题:Java 接口的异常设计疑惑
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-11-12
抛出抽象异常
比如 baseAbstractException- 下有两个异常 一个sysE一个bussE 然后所有异常从这两个异常扩展 |
|
返回顶楼 | |
发表时间:2009-11-12
最后修改:2009-11-12
czpsailer 写道 在接口有多个不同的实现类时,不同的实现又可能抛出不同的异常,这样就无法在接口声明中将这些具体异常全部声明出来了,这时候使用一个抽象的异常就比较可行了。可是如果这样的话,我觉的使用接口的地方,就无法明确到底会出现哪些具体的异常了。这样貌似异常的使用原则(尽量指定具体的异常)有些相违背了。
这个接口本身都不知道会抛出什么异常,为什么还要向上抛出呢?(除非是上层调用可以处理的异常),自己都不确定的,上一层更没法知道怎么处理你这些异常了。不如就在本层处理,或者转成运行时异常。 |
|
返回顶楼 | |
发表时间:2009-11-12
看了各位高手的回复后有点自己的看法:不赞成为业务需要而设计自定义异常类的做法(如余额不足、没有权限等),因为异常处理的开销比较大。鄙人认为业务上的问题还是通过普通的逻辑判断进行处理比较妥当。
|
|
返回顶楼 | |
发表时间:2009-11-12
Dreamer 写道 看了各位高手的回复后有点自己的看法:不赞成为业务需要而设计自定义异常类的做法(如余额不足、没有权限等),因为异常处理的开销比较大。鄙人认为业务上的问题还是通过普通的逻辑判断进行处理比较妥当。
与IO、数据库访问相比,1ms的消耗应该不在考虑范围内。 是否需要定义异常,与你的设计、职责划分很有关系:还是以取款为例,如果你要求别人在调用之前,必须先检查好金额、权限等所有异常,你可以不考虑异常。 但从程序的Robust、从简化使用的角度,一般还是要去考虑的,不能把所有的前置条件、后置条件都交给调用方 |
|
返回顶楼 | |
发表时间:2009-11-12
pipilu 写道 czpsailer 写道 在接口有多个不同的实现类时,不同的实现又可能抛出不同的异常,这样就无法在接口声明中将这些具体异常全部声明出来了,这时候使用一个抽象的异常就比较可行了。可是如果这样的话,我觉的使用接口的地方,就无法明确到底会出现哪些具体的异常了。这样貌似异常的使用原则(尽量指定具体的异常)有些相违背了。
这个接口本身都不知道会抛出什么异常,为什么还要向上抛出呢?(除非是上层调用可以处理的异常),自己都不确定的,上一层更没法知道怎么处理你这些异常了。不如就在本层处理,或者转成运行时异常。 这个是在稳定性与灵活性上去权衡:有一个基础类,可以保持接口稳定,让不同使用场景自行去约定异常。只有通用接口才有这样的需求,一般是框架类。具体子类实现的时候,还需要与使用者自行去约定异常。 一般业务逻辑中,专用接口,则需要详细定义异常。 |
|
返回顶楼 | |
发表时间:2009-11-12
统一异常类型,比如自定义一个 ServiceException
|
|
返回顶楼 | |
发表时间:2009-11-12
具体问题具体分析了,业务规定啥样的异常就要抛啥异常,接口只是一个规则, 看具体的规则,如果你的接口比较通用那么抛出的异常也要通用,就是异常尽量要大一点就是exception 然后实现类抛的异常更具体一点,如nullpointexception等等
|
|
返回顶楼 | |
发表时间:2009-11-12
joachimz 写道 pipilu 写道 czpsailer 写道 在接口有多个不同的实现类时,不同的实现又可能抛出不同的异常,这样就无法在接口声明中将这些具体异常全部声明出来了,这时候使用一个抽象的异常就比较可行了。可是如果这样的话,我觉的使用接口的地方,就无法明确到底会出现哪些具体的异常了。这样貌似异常的使用原则(尽量指定具体的异常)有些相违背了。
这个接口本身都不知道会抛出什么异常,为什么还要向上抛出呢?(除非是上层调用可以处理的异常),自己都不确定的,上一层更没法知道怎么处理你这些异常了。不如就在本层处理,或者转成运行时异常。 这个是在稳定性与灵活性上去权衡:有一个基础类,可以保持接口稳定,让不同使用场景自行去约定异常。只有通用接口才有这样的需求,一般是框架类。具体子类实现的时候,还需要与使用者自行去约定异常。 一般业务逻辑中,专用接口,则需要详细定义异常。 有道理。 这种情况下,我倾向于交由实现类来自行决定抛出运行时异常,使用接口的开发人员通过阅读文档来了解实现类可能会抛出的异常。避免异常声明给调用者带来负担。 |
|
返回顶楼 | |
发表时间:2009-11-12
最后修改:2009-11-12
查看了一些关于Exception的讨论,发现对于如何何时处理异常和使用Checked Exceptions还是Unchecked Exceptions是讨论很激烈的话题呀!如何很好的处理和使用异常,的确是一件不容易的事情?好多时候容易使人感到疑惑! joachimz写道
接口就是约定,异常是返回结果之一。
对于系统性异常,例如网络可能中断,未知的程序错误等等,这种处理成运行时异常,不作申明比较好,反正接收的人也没办法做任何处理 对于有业务性的错误,例如取款时,余额不够、权限不够、超出最大取款限制等等,这类错误,最好,每个场景,定义一个异常,在申明中逐一说明,总之,异常是帮助使用者了解、处理不同的错误场景。使用者可以根据错误类型的不同,给用户提供不同的处理方式和流程。当然,如果你提供给用户的只是提示信息,就没必要再区分类型了 异常处理方式上,还有一个办法是对异常编码,那就只需要一种类型了,类似SqlException。两种方式都可行,重点是要让约定更加明确、翔实
注:AbstractBusinessException继承自Exception,SpecificBusinessException1,SpecificBusinessException2 继承AbstractBusinessException。
使用方式一:
每个具体的业务异常类(如SpecificBusinessException1这样的)本身表示具体的一个业务错误,而接口声明的AbstractBusinessException只是为了能在子类中抛出具体的业务异常。带来的好处之一是当以后发现需要添加新的业务错误(添加新的业务异常)时候,无需修改客户端代码。
我觉得这种使用方式是不合理的,这样其实把一个接口方法的责任约定方式到了不同的地方(实现类的方式签名中)。接口的实现是无法预期的,客户端难以在出现异常时候确定具体是那个错误(除非客户端程序员能够获取到并且阅读所有的实现类(包括现在实现和将来实现)的API,但这是不可能的)并且进行相应的处理,此时的异常仅仅是对业务执行的错误的指示,无法成为进行恢复或近一步操作的指示。这种方式不值得提倡,因为我们应该在前期就透却全面的分析业务,避免出现遗漏业务流程的情况存在;而对于业务的变更,则应该选择重构。
使用方式二:
对异常编码,子类只是简单的包含不同的错误码,定义一个统一的异常字典。客户端获取异常后获取到错误码根据其进行相应处理。
以下为耶鲁CAS的中的代码摘要:
public abstract class AuthenticationException extends Exception {
我觉得这种使用方式就比较合理了,不过这种合理性同样是建立在前期对业务的透却全面的分析基础上。
|
|
返回顶楼 | |
发表时间:2009-11-12
最后修改:2009-11-12
pipilu 写道 joachimz 写道 pipilu 写道 czpsailer 写道 在接口有多个不同的实现类时,不同的实现又可能抛出不同的异常,这样就无法在接口声明中将这些具体异常全部声明出来了,这时候使用一个抽象的异常就比较可行了。可是如果这样的话,我觉的使用接口的地方,就无法明确到底会出现哪些具体的异常了。这样貌似异常的使用原则(尽量指定具体的异常)有些相违背了。
这个接口本身都不知道会抛出什么异常,为什么还要向上抛出呢?(除非是上层调用可以处理的异常),自己都不确定的,上一层更没法知道怎么处理你这些异常了。不如就在本层处理,或者转成运行时异常。 这个是在稳定性与灵活性上去权衡:有一个基础类,可以保持接口稳定,让不同使用场景自行去约定异常。只有通用接口才有这样的需求,一般是框架类。具体子类实现的时候,还需要与使用者自行去约定异常。 一般业务逻辑中,专用接口,则需要详细定义异常。 有道理。 这种情况下,我倾向于交由实现类来自行决定抛出运行时异常,使用接口的开发人员通过阅读文档来了解实现类可能会抛出的异常。避免异常声明给调用者带来负担。 这样其实有个问题,因为你无法阅读到所有的实现类的API文档和无法很好的预期运行是客户端会调用的那个实现类。 例如:当前已知有2个实现类声明了3个具体的异常。此时你的客户端程序可以很好的处理这些异常,当时如果那天有了一个新的实现类并且他声明了一个新的异常,你的客户端就不知道应该如果处理了。 不过貌似对于一个通用的接口,一般比较难对所有的实现进行预期,也就无法在接口定义的时候就声明所有的异常,那么是声明一个比较抽象的异常还是使用非受检异常呢,那就仁者见仁了。 |
|
返回顶楼 | |