《Effective Java》——异常

只针对异常情况才使用异常

异常设计的初衷就是针对程序的不正常情形所使用的,不要使用异常来控制程序的执行流程

对可恢复的情况使用受检异常,对编程错误使用非受检异常

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异常都使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值