第十章,异常
讨论异常,充分发挥异常的优点,可以提高程序的可读性、可靠性、可维护性
第六十九条 ,只针对异常的情况才使用异常
1.异常应该只用于异常的情况下,他们永远不应该用于正常的控制流
2.设计良好的API不应该强迫它的客户端为了正常的控制流而使用异常,提供一个方法测试,比如迭代器的hasNext()或者
提供返回optional,null
第七十条,对可恢复的情况使用受检异常,对编程错误使用运行异常
1.java提供了受检异常,运行异常和错误
2.如果期望调用者能够适当的恢复,对于这种情况就应该使用受检异常,可以提供方法,以便协助恢复
3.用运行时异常来表明编程错误,你实现的所有未受检的异常结构都是RunTimeException的子类
第七十一条,避免不必要地使用受检异常
1.受检异常需要调用者try-catch去处理这些异常,会带来不便,stream中还不能直接使用抛出受检异常的方法
2.如果正确的使用API并不能阻止这种异常的产生,并且一旦产生异常,使用API的程序员可以立即采用有用的动作
抛出受检异常才让人接受
3.消除受检异常的方法
1.返回optional,确点是无法返回导致失败的原因,异常确可以
2.提供一个测试方法,比如hasNext ,但是如果多线程调用,会改变对象的状态,则不建议这样做
第七十二条,优先使用标准的异常
1.IllegalArgumentException,传递参数不符合
2.IllegalStateException,表示方法已在非法或不适当的时间被调用
3.IndexOutOfBoundsException 下标越界
4.ConcurrentModificationException当线程使用的类,在多线程并发的修改
5.UnsupportedOperationException,不支持的方法
6.不直接重要Exception,RunTimeException,Throwable或者Error
7.如果没有可用的参数值,就抛出IllegalStateException,否则就跑出IllegalArgumentException
第七十三条,抛出与抽象对应的异常
1.更高层的实现应该捕获低层的异常,同时抛出可以按照高层抽象进行解析的异常
public E get(int index) {
try {
return listIterator(index).next();
//捕获低层异常
} catch (NoSuchElementException exc) {
//抛出高层的异常
throw new IndexOutOfBoundsException("Index: "+index);
}
}
2.传递异常信息, throw new IndexOutOfBoundsException("异常信息,可以传递")
3.尽管异常转译与不加选择地从低层传递异常的做法相比有所改变,但是也不能滥用
第七十四条,每个方法抛出的异常都要简立文档
1.始终要单独地声明受检异常,并且利用javadoc的@throws标签,准确地记录下抛出每个异常的条件
2.利用javadoc的@throws标签记录一个方法可能抛出的每个未受检的异常,但是不要使用throws关键字将未受检的异常
包含在方法的声明中
3.如果一个类的许多方法出于同一个原因而抛出同一个异常,在该类的文档注释中对这个异常建立文档,这是可以
接受的
第七十五条,在细节消息中包含失败-捕获信息
1.为了捕获失败,异常细节信息应该包含“对该异常有贡献”的所有参数和域的值
2.千万不要在细节消息中包含密码,秘钥以及类似的信息
3.提供具体的参数构造器,替换String的构造器,比如IndexOutputException(String)->IndexOutputException(int lower,int upper,int index)
第七十六条,努力使失败保持原子性
1.一般而然,失败的方法调用应该使对象保持在被调用之前的状态,具有这种属性的方法被称为失败原子性
2.实现失败原子性方法
1.不可变的对象,状态只有在创建的时候确定
2.在执行操作之前检查参数的有效性
3.使任何可能导致失败额计算在修改状态之前进行执行
4.在对象的一个临时拷贝上操作,操作完成后再把临时拷贝对象的结果替代对象的内容
5.提供恢复代码,恢复失败前的状态,这种主要用在永久性(基于磁盘的)数据结构
3.如果无法做到失败原子性,应该在文档中说明对象将会处在什么状态
第七十七条,不要忽略异常
1.空的catch块使异常达不到应有的目的
2.如果选中忽略异常,catch块中应该包含一条注释,说明为什么可以这么做,而且变量应该命名为ignore