只针对异常情况才使用异常
异常设计的初衷就是针对程序的不正常情形所使用的,不要使用异常来控制程序的执行流程
对可恢复的情况使用受检异常,对编程错误使用非受检异常
Java设计了三种可以抛出的结构
- checked exception
- runtim exception
- error
error一般情况下,约定俗称有虚拟机使用,表示资源不足等错误
对可恢复的情况使用受检异常,对编程错误使用非受检异常
避免不必要的使用checked exception
使用checked exception会给客户端程序员带来很大的负担,只有满足如下两个条件,才应该使用checked exception
- 即使正确调用该api此种情况也可能发生
- 对于异常的发生,程序员可以立即采取有用的动作
否则,应该使用runtime exception
优先使用标准的异常
重用现有的异常,有三个好处
- 使你的api易于学习和使用
- 对于使用api的程序来说,可读性会更好
- 异常类越少,装载时的开销也越小
常用的异常有如下几个
- IllegalArgumentException
- IllegalStateException
- NullPointerException
- IndexOutOfBoundException
- ConcurrentModificationException
- UnsupportedOperationException
抛出与抽象相对应的异常
当方法要传递底层实现抛出的异常时,要进行异常转译,不要使底层实现的异常污染了上层api
例如
catch(IOException e){
throw new ServiceException(e);
}
通常有两种转译方式,一种是直接异常的转译,一种是异常链的转译
上面的例子就是异常链的转译,调用方可以通过异常获得更底层的异常,方便排查问题,直接转译就是不传递异常链,例如
catch(IOException e){
throw new ServiceException("io exception");
}
以上只是针对一定要传递底层异常情况下的处理方法,对于底层的方法,首选方案是处理掉底层异常,不将异常的影响传递到上层去,一般有两条途径来实现
- 对参数进行检查,避免调用底层方法发现异常
- 绕开异常,将异常记录下来,不传播出去
每个方法抛出的异常都要有文档
为checked exception和unchecked exception都建立文档说明,但是不要在方法声明中标记unchecked exception
在细节消息中包含能捕获失败的信息
要记录下产生该异常的各种原因,最好能使异常自身记录下产生问题的原因,例如在异常的构造函数中包含一些特别的字段,就像在IndexOutOfBoundsException中可以有如下构造方法
public IndexOutOfBoundsException(int lowerBound, int upperBound, int index){
...
努力使失败保持原子性
失败的方法调用应该使对象保持在被调用之前的状态,有几种途径可以实现这个目的
- 使用不可变对象
- 在改变状态之前检查参数有效性,提前抛出异常
- 将可能失败的操作放在改变状态之前执行,这样失败是可以提前结束,不至于使对象处于不一致的状态
- 写恢复代码(不常用),一般是对于已经持久化的数据
- 使操作在一个临时拷贝上执行
有时,并不总能实现失败的原子性,例如两个线程不安全的并发修改对象的状态
规范上来讲,任何调用失败都应该使对应状态位于之前的状态,如何有不一致,应该在文档中描述出来
不要忽略异常
对于异常,除了关闭InputStream时,其他时候都不要忽略异常
对异常
- 要么处理
- 要么传播出去
此建议对于checked 和unchecked异常都使用
版权声明:本文为博主原创文章,未经博主允许不得转载。