RuntimeException和Exception比较
自定义异常是继承RuntimeException还是继承Exception
Java Exception分为两种
- 一种是不可检查异常uncheked exception,可检查异常在代码中显示的捕获,如果不捕获,编译期会报错。
- 另一种是可检查异常checked exception,不可检查异常编译期不会检测,此类异常是运行时异常。
区别
- RuntimeException是Exception的子类,但是虚拟机在处理异常的时候对他们做了区分。
- 自定义异常如果继承RuntimeException,这样的异常spring可以进行事务回滚。
例:一个方法报异常,另一个方法回滚在catch语句中最后增加thrownewRuntimeException()语句,以便让aop捕获异常再去回滚,并且在service上层(webservice客户端,view层action)要继续捕获这个异常并处理try { userDao.save(user); userCapabilityQuotaDao.save(capabilityQuota); } catch (Exceptione) { thrownewRuntimeException(); }
- TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常了
在service层方法的catch语句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常了try { userDao.save(user); userCapabilityQuotaDao.save(capabilityQuota); } catch (Exceptione) { TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); }
- 自定义异常如果继承Exception,这样的异常spring不支持事务回滚。但是可以显示在方法上声明@Transactional(rollbackFor=Exception.class) //指定回滚,遇到异常Exception时回滚。
例:一个方法报异常,另一个方法不会回滚try { userDao.save(user); userCapabilityQuotaDao.save(capabilityQuota); } catch (Exceptione) { } trycatch这种把整个包裹起来,这种业务方法也就等于脱离了spring事务的管理,因为没有任何异常会从业务方法中抛出,全被捕获并“吞掉”,导致spring异常抛出触发事务回滚策略失效。
继承Execption类的优缺点
- 优点:异常总能被捕获,抛出的异常必须呗try-catch显示的捕获处理。
- 缺点:因为异常必须被捕获或者要么继续向上层抛出,表现出:要么满屏的try-catch或者整个链路方法的后面全是throws Exception不美观,也导致方法耦合严重,一旦最内层方法不抛出异常了,外层方法全要修改。
继承RuntimeExecption类优缺点
- 优点:抛出的异常可以不处理。
- 缺点:对于必须处理的异常如果被声明成了RuntimeException,比如涉及到金额,调用方未捕获异常继续处理,就会导致业务出错。
如何选择
- 减少程序耦合,自定义为RuntimeException,但是和团队约定好:某某异常一定要在哪一层捕获。 如果某个异常不想处理,无关紧要,但是要做好日志记录。
- 当你是程序级别接口提供者,一定要抛出Exception,这样调用方即使不约定也一定会捕获这个异常。 涉及数据库事务一定要声明RuntimeException,提供服务级接口一定抛出Exception。
- 例如我要写一个java api,这个api中会调用一个极其操蛋的远端服务,这个远端服务经常超时和不可用。所以我决定以抛出自定义异常的形式向所有调用这个api的开发人员周知这一操蛋的现实,让他们在调用这个api时务必考虑到远端服务不可用时应该执行的补偿逻辑(比如尝试调用另一个api)。此时自定义的异常类就应继承Exception,这样其他开发人员在调用这个api时就会收到编译器大大的红色报错:【你没处理这个异常!】,强迫他们处理。
- 又如,我要写另一个api,这个api会访问一个非常非常稳定的远端服务,除非有人把远端服务的机房炸了,否则这个服务不会出现不可用的情况。而且即便万一这种情况发生了,api的调用者除了记录和提示错误之外也没有别的事情好做。但出于某种不可描述的蛋疼原因,我还是决定要定义一个异常对象描述“机房被炸”这一情况,那么此时定义的异常类就应继承RuntimeException,因为我的api的调用者们没必要了解这一细微的细节,把这一异常交给统一的异常处理层去处理就好了。