Effective Java 第三版——76. 争取保持失败原子性
Tips
书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code
注意,书中的有些代码里方法是基于Java 9 API中的,所以JDK 最好下载 JDK 9以上的版本。

76. 争取保持失败原子性
在对象抛出异常之后,通常希望对象仍然处于定义良好的可用状态,即使失败发生在执行操作中。对于检查异常尤其如此,调用者希望从检查异常中恢复。一般来说,失败的方法调用应该使对象处于调用之前的状态。具有此属性的方法称为失败原子性( failure-atomic)。
有几种方法可以达到这种效果。最简单的方法是设计不可变对象(条目 17)。如果对象是不可变的,则失败原子性是必然的。如果一个操作失败,它可能会阻止创建一个新对象,但是它不会让一个现有对象处于不一致的状态,因为每个对象的状态在创建时是一致的,并且在创建后不能修改。
对于对可变对象进行操作的方法,实现失败原子性的最常用方法是:在执行操作之前检查参数的有效性(条目 49)。 这导致在对象修改开始之前就会抛出大多数异常。 例如,考虑条目 7中的Stack.pop方法:
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}
如果取消了初始大小检查,当该方法试图从空栈中弹出元素时,仍然会抛出异常。但是,这会使size属性处于不一致的(负数)状态,导致以后对对象的任何方法调用失败。此外,pop方法抛出的ArrayIndexOutOfBoundsException针对抽象来讲是不合适的。(条目 73)。
实现失败原子性的一种密切相关的方法是对计算进行排序,以便任何可能失败的部分在修改对象的部分之前发生。 在执行部分计算时进行参数检查,此方法是前一个方法的自然扩展。 例如,考虑TreeMap的情况,其元素按照某种顺序排序。 为了向TreeMap添加元素,元素必须是可以使用TreeMap的顺序进行比较的类型。 在以任何方式修改tree之前,尝试添加错误键的元素自然会因为在tree中搜索元素失败而导致ClassCastException异常。
实现失败原子性的第三种方法是,在对象的临时拷贝上执行操作,并在操作完成后用临时拷贝替换对象的内容。当数据存储在临时数据结构中后,计算可以更快地执行时,这种方法自然会出现。例如,一些排序方法在排序之前将其输入列表拷贝到数组中,以降低访问排序内循环中的元素的成本。这样做是为了提高性能,但是作为一个额外的好处,它确保如果排序失败,输入列表保持不变。
实现失败原子性的最后的方法是,编写恢复代码(recovery code),但这种做法并不长用,该代码拦截在操作中发生的失败,并使对象将其状态回滚到操作开始之前的点。 此方法主要用于持久性的(基于磁盘)的数据结构。
虽然失败原子性通常是可取的,但它并不总是可以实现的。例如,如果两个线程试图在没有适当同步的情况下并发地修改同一个对象,那么该对象可能会处于不一致的状态。因此,如果假定在捕捉到ConcurrentModificationException之后对象仍然可用,那就错了。错误是不可恢复的,所以方法在抛出AssertionError时,甚至不需要尝试保存失败原子性。
即使在可能存在实现失败原子性的情况下,也并非总是可取的。 对于某些操作,它会显着增加成本或复杂性。 也就是说,一旦你意识到这个问题,通常都可以自由而轻松地做到失败原子性。
总之,作为规则,任何生成的异常都是方法规范的一部分,应该使对象处于方法调用之前的状态。 违反此规则的地方,API文档应清楚地指出该对象将保留在哪种状态。遗憾的是,许多现有的API文档无法实现这一理想。
Effective Java 第三版——76. 争取保持失败原子性的更多相关文章
- 《Effective Java 第三版》新条目介绍
版权声明:本文为博主原创文章,可以随意转载,不过请加上原文链接. https://blog.csdn.net/u014717036/article/details/80588806前言 从去年的3月份 ...
- 《Effective Java 第三版》目录汇总
经过反复不断的拖延和坚持,所有条目已经翻译完成,供大家分享学习.时间有限,个别地方翻译得比较仓促,希望有疑虑的地方指出批评改正. 第一章简介 忽略 第二章 创建和销毁对象 1. 考虑使用静态工厂方法替 ...
- Effective Java 第三版——49. 检查参数有效性
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——1. 考虑使用静态工厂方法替代构造方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——3. 使用私有构造方法或枚类实现Singleton属性
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——7. 消除过期的对象引用
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——9. 使用try-with-resources语句替代try-finally语句
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——10. 重写equals方法时遵守通用约定
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Effective Java 第三版——11. 重写equals方法时同时也要重写hashcode方法
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
随机推荐
- 大数据小白系列——HDFS(1)
[注1:结尾有大福利!] [注2:想写一个大数据小白系列,介绍大数据生态系统中的主要成员,理解其原理,明白其用途,万一有用呢,对不对.] 大数据是什么?抛开那些高大上但笼统的说法,其实大数据说的是两件 ...
- ELK日志分析方案
针对公司项目微服务化,随着项目及服务器的不断增多,决定采用ELK(Elasticsearch+Logstash+Kibana)日志分析平台进行微服务日志分析. 1.ELK整体方案 1.1 ELK架构图 ...
- XamarinSQLite教程下载安装SQLite/SQL Server Compact Toolbox
XamarinSQLite教程下载安装SQLite/SQL Server Compact Toolbox SQLite/SQL Server Compact Toolbox是一个Visual Stud ...
- XamarinAndroid组件教程RecylerView自定义适配器动画
XamarinAndroid组件教程RecylerView自定义适配器动画 如果RecyclerViewAnimators.Adapters命名空间中没有所需要的适配器动画,开发者可以自定义动画.此时 ...
- Shell脚本笔记(三)shell中的数学计算
shell中的数学计算 一.使用方括号 #!/bin/bash a= b= c= res=$[$a * ($c-$b)] echo $res 二.使用(()) +)) ((i=+)) b=$((-*) ...
- css selector 用法
html.css('a::attr(href)').extract()
- mongoose事务操作,参考官网
https://docs.mongodb.com/manual/reference/method/db.collection.bulkWrite/ await model.photo.bulkWrit ...
- 第2讲——wiz
PC端信息收集 网页剪藏 win+s 屏幕截图:win+printscreen微博收集:@mywiz @我的印象笔记 按ESC隐藏/恢复左边导航栏 F11全屏阅读 打标签:解决文件夹重叠问题 搜索 ...
- hiredis 使用 linux c++
1.linux下如何安装hiredis 1)下载地址 https://github.com/redis/hiredis 2)编译和安装 解压后的文件夹执行 make;make install; 3) ...
- JS_高阶函数(sort)
//javaScript sort()排序算法 //sort()方法默认把所有的元素转换成String再排序,字符串是根据ASCII进行排序的,所以会出现“10”排在“2”前面,或是小写字母“a”排在 ...