Effective Java(2 Edition) Item 64译文

Item64:为failure atomicity而努力

 

如果一个对象抛出了异常,就算错误发生在运算过程之中,通常还是需要对象处于定义良好、可用的状态。对受检查的异常更是如此, 因为总是希望调用者能从异常处恢复运行。一般说来,失败的方法调用应能使相关对象的状态在该方法调用前后保持一致。称具有这种特质的方法为failure atomic

有几种方法可以做到failure atomic。最简单的方法是设计一个类为不变类(Item 15)。对不变类,可以免费获得failure atomicity。因为不变类的对象在创建之后不能修改其状态,从而始终保持了状态一致,所以,失败的运算可能阻止创建了一个新对象,但永远不会使已存在的对象处于不一致的状态。

如果要对可变对象进行运算,要获得failure atomic,最常用的方法是在作运算前检查参数的有效性(Item 38)。这样,在对象的状态被修改前就抛出可能的异常。例如,考虑Item 6中的Stack.pop方法:

public Object pop() {

       if (size == 0)

              throw new EmptyStackException();

       Object result = elements[--size];

       elements[size] = null; // Eliminate obsolete reference

       return result;

}

如果取消了开始对size变量的检查,则在空Stack弹出一个元素时,该方法仍然会抛出异常,但此时却导致size变量为负数,并处于不一致状态,将来调用该对象上的方法时也会导致失败。另外,pop方法抛出的异常也不适合于关于Stack的抽象。

获得failure atomicity特性并与上面方法紧密相关的方法是将计算置后,即将可能出现错误的代码在修改对象之前运行。若先要对参数进行验证,接着才能对参数进行计算,这个方法就是前一方法的自然扩展。例如,考虑TreeMap的例子,其元素按一定的次序排序。要在TreeMap中增加一个元素,这个元素就必须能使用TreeMap的次序进行比较。若当前元素不能与TreeMap中的已有元素进行比较,则自然要抛出ClassCastException,而这些都是在对TreeMap中的元素作任何修改之前完成的。

获得failure atomicity的第三种方法并不常用。该方法是写恢复代码,这种方法拦截运算过程中的错误,并将对象的状态回滚到运算开始前的状态,这种方法主要用于基于磁盘的持久化数据结构。

获得failure atomicity的最后一种方法是在对象的临时拷贝上进行运算,运算完成之后再用临时对象上的数据替换原来的对象,如果将数据存储在一个临时的数据数据上可以加快运算的话,则这就是一个自然的方法。例如,Collections.sort在排序前将所输入的list导入一个数组,这减少了排序时内循环访问元素的开销,虽然这样做是出于性能考虑,但也有一个额外的好处,即这样做保证了如果排序失败,则所输入的list没有被改变。

虽然一般说来,我们需要failure atomicity,但并不是总是可以获得。例如,如果两个线程要并发地修改同一个对象,而又没有正确地使用synchronization的话,这个对象就可能处于不一致的状态,因此在捕获到ConcurrentModificationException后,如果还认为该对象是可用的,就可能会发生错误。通常,错误(相对应的是异常)是不可恢复的,方法中抛出错误时,并不需要方法有failure atomicity特性。

就算可以得到failure atomicity,也并不总是需要的。对某些运算,这会极大地增加成本与复杂度。尽管如此,如果你能意识到failure atomicity特性,要获得它就是容易的并且是免费的。

一般说来,如果方法中产生的异常是方法规范中的一部份,这个异常应该使对象的状态处于方法调用前的状态,如果背离了这个规则,则文档应明确说明异常发生后对象所处的状态。不幸的是,现存的许多文档没有做到这一点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值