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. 争取保持失败原子性的更多相关文章

  1. 《Effective Java 第三版》新条目介绍

    版权声明:本文为博主原创文章,可以随意转载,不过请加上原文链接. https://blog.csdn.net/u014717036/article/details/80588806前言 从去年的3月份 ...

  2. 《Effective Java 第三版》目录汇总

    经过反复不断的拖延和坚持,所有条目已经翻译完成,供大家分享学习.时间有限,个别地方翻译得比较仓促,希望有疑虑的地方指出批评改正. 第一章简介 忽略 第二章 创建和销毁对象 1. 考虑使用静态工厂方法替 ...

  3. Effective Java 第三版——49. 检查参数有效性

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  4. Effective Java 第三版——1. 考虑使用静态工厂方法替代构造方法

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  5. Effective Java 第三版——3. 使用私有构造方法或枚类实现Singleton属性

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  6. Effective Java 第三版——7. 消除过期的对象引用

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  7. Effective Java 第三版——9. 使用try-with-resources语句替代try-finally语句

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  8. Effective Java 第三版——10. 重写equals方法时遵守通用约定

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  9. Effective Java 第三版——11. 重写equals方法时同时也要重写hashcode方法

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

随机推荐

  1. 【python】进程与线程

    No1: 多进程 from multiprocessing import Process import os # 子进程要执行的代码 def run_proc(name): print('Run ch ...

  2. CodeForces - 893C Rumor【并查集】

    <题目链接> 题目大意: 有n个人,其中有m对朋友,现在你有一个秘密你想告诉所有人,第i个人愿意出价a[i]买你的秘密,获得秘密的人会免费告诉它的所有朋友(他朋友的朋友也会免费知道),现在 ...

  3. 基于netty的websocket例子

    nettyServer package com.atguigu.netty.websocket; import javax.annotation.PostConstruct; import org.s ...

  4. ENQUIRE the predecessor to the World Wide Web.

    看Building Responsive Data Visualization for the Web时介绍到了Enquire,表示wiki类系统实现了它的核心思想. 有点好奇是如何实现的,所以大概看 ...

  5. Java代码优化小结(三)

    (35)对资源的close()建议分开操作虽然有些麻烦,却能避免资源泄露.我们想,如果没有修改过的代码,万一XXX.close()抛异常了,那么就进入了catch块中了,YYY.close()不会执行 ...

  6. MySql基础笔记(二)Mysql语句优化---索引

    Mysql语句优化--索引 一.开始优化前的准备 一)explain语句 当MySql要执行一个查询语句的时候,它首先会对语句进行语法检查,然后生成一个QEP(Query Execution Plan ...

  7. [机器学习入门篇]-Logistic函数与Softmax函数

    1.Logistic函数 在维基百科中,对logistic函数这样介绍道: A logistic function or logistic curve is a common "S" ...

  8. BZOJ4867 : [Ynoi2017]舌尖上的由乃

    首先通过DFS序将原问题转化为序列上区间加.询问区间kth的问题. 考虑分块,设块大小为$K$,每块维护排序过后的$pair(值,编号)$. 对于修改,整块的部分可以直接打标记,而零碎的两块因为本来有 ...

  9. Moo University - Financial Aid [POJ2010] [堆]

    题意: 在C头牛里选N头牛,每头牛需要花掉一定经费ai才能得到一定得bi分,在不超过经费F的情况下,使得N头牛的得分中位数最大.(1 <= N <= 19,999,奇数) (N <= ...

  10. chrome浏览器下载内容存放位置

    点击: 或者直接快捷键 ctrl +J 打开下载的资料在[设置]中可将浏览器设置成默认浏览器,更换下载内容的存放位置:给一个提示,本人未曾修改下载的存放位置,是用户/Administrator/Dow ...