前言:在自行学习自定义异常时,遇到个问题:
抛出继承RuntimeException的自定义异常,不需要在方法处throws声明,调用该方法时也不需强制处理异常。
而抛出继承Exception的自定义异常,则恰恰相反。必须在方法上主动throws声明,调用该方法时也必须强制处理:捕获或抛出。
本篇文章对以上问题进行回答。
一、概念说明
- 在java的异常类体系中,Error和RuntimeException是非检查型异常,其他的都是检查型异常。
- 所有方法都可以在不声明throws的情况下抛出RuntimeException及其子类 。
- 不可以在不声明的情况下抛出非RuntimeException。
- 简单的说,非RuntimeException必要自己写catch块处理掉,或再次抛出。
- RuntimeException不用try catch捕捉将会导致程序运行中断,若用则不会中断。
- 对于RuntimeException的子类最好也使用异常处理机制。虽然RuntimeException的异常可以不使用try...catch进行处理,但是如果一旦发生异常,则肯定会导致程序中断执行,所以,为了保证程序再出错后依然可以执行,在开发代码时最好使用try...catch的异常处理机制进行处理。
二、网上回答
2.1 回答一
继承Exception还是继承RuntimeException是由异常本身的特点决定的,而不是由是否是自定义的异常决定的。
例如我要写一个java api,这个api中会调用一个极其操蛋的远端服务,这个远端服务经常超时和不可用。所以我决定以抛出自定义异常的形式向所有调用这个api的开发人员周知这一操蛋的现实,让他们在调用这个api时务必考虑到远端服务不可用时应该执行的补偿逻辑(比如尝试调用另一个api)。此时自定义的异常类就应继承Exception,这样其他开发人员在调用这个api时就会收到编译器大大的红色报错:【你没处理这个异常!】,强迫他们处理。
又如,我要写另一个api,这个api会访问一个非常非常稳定的远端服务,除非有人把远端服务的机房炸了,否则这个服务不会出现不可用的情况。而且即便万一这种情况发生了,api的调用者除了记录和提示错误之外也没有别的事情好做。但出于某种不可描述的蛋疼原因,我还是决定要定义一个异常对象描述“机房被炸”这一情况,那么此时定义的异常类就应继承RuntimeException,因为我的api的调用者们没必要了解这一细微的细节,把这一异常交给统一的异常处理层去处理就好了。
2.2 回答二
规范里说明,Java Exception分为两种, unchecked exception 和 checked exception 显然,前者是运行时异常继承自RuntimeException,后者受控异常继承自Exception。
2.3 回答三
对抛出的异常,checked exception要与方法耦合,尤其是接口中定义的方法影响比较大,使用起来不够灵活。不抛出异常,就得满屏的try-catch。
我现在的做法是除非抛出的异常需要调用层显式处理,否则自定义异常都继承RuntimeException,在最上层的调用统一做一次try-catch。这样一来方法的声明和使用简洁了很多。
其实,我觉得最重要的还是团队的约定。
2.4 回答四
尽量继承RuntimeException。这么做可以降低代码间的耦合性,你想,如果继承Exception(或者其它受查异常),万一原来抛出异常的那个方法不再抛出异常了呢?岂不是接口、以及所有的上层调用方法中的try-catch都得改?
而且太多受查异常很容易把代码搞乱。
参考:
https://www.zhihu.com/question/51970444
https://www.cnblogs.com/zhuyeshen/p/10907800.html