读书笔记:Effective Java-第10章 异常

11 篇文章 0 订阅
11 篇文章 0 订阅

目录

Item 69: Use exceptions only for exceptional conditions

Item 70: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors

Item 71: Avoid unnecessary use of checked exception

Item 72: Favor the use of standard exceptions

Item 73: Throw exceptioons appropriate to the abstraction

Item 74: Document all exceptions thrown by each method

 Item 75: Include failure-capture information in detail messages

Item 76: Strive for failure atomicity

Item  77: Don't ignore exception


Item 69: Use exceptions only for exceptional conditions

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

异常模式比正常模式要慢。

用异常来代替正常控制流的弊端:可读性差,降低性能,不能保证正常工作,掩盖其他bug。

Item 70: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors

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

术语

  • precondition violation:前提违例,指API的客户没有遵守API规范建立的约定。

java提供了3种可抛出结构throwables:受检异常checked exception、运行时异常runtime exception、错误error。

1种受检的throwables:checked exception。受检异常的目的是强制用户要从异常中恢复。

2种不受检的throwables:runtime exception、error。它们不需要也不应该被捕获。当抛出这2种异常时,往往就是不可恢复的场景,程序继续执行下去有害无益。

throwable不捕获的影响:当前线程中断,生成适当的错误信息。

runtime exception用来表示编程错误。大多数表示前提违例(precondition violation)

难点:很难判断要处理的情况是可恢复的还是不可恢复的。如资源枯竭,有可能是分配不合理的大数组造成的(可恢复),也可能是资源不足导致的(不可恢复)。

针对难以判断是否可恢复的情况,最好用runtime exception。

error往往被JVM保留下来使用,用于资源不足、约束失败等等,且这几乎是被普遍接受的惯例。所以在编程中应该定义和使用的unchecked throwable只能是RuntimeException的子类,不应该定义和使用Error的子类。

checked exception需提供一些辅助方法,帮助调用者获取一些有助于恢复的信息。例如,用户购买礼品时因资金不足而抛出一个受检异常,这个异常应该提供一个查询所缺金额的方法method,使调用者可以将这个数值传递给用户。

Item 71: Avoid unnecessary use of checked exception

避免不必要地使用受检异常

相比其他异常,受检异常可提高程序的可靠性,但会增加程序员的开发负担,且不能直接用到stream中。

因此可以考虑采用以下方法代替受检异常:

  • (优先考虑)用Optional代替。
  • 新增一个函数封装抛出异常的函数,用boolean的返回值区分是否发生异常。

代替受检异常方案的弊端:无法提供足够的异常信息。

Item 72: Favor the use of standard exceptions

优先使用标准异常

java类库提供了一组覆盖大多数API场景的标准异常。

不要直接重用Throwable、Exception、RuntimeException和Error,把它们当做抽象类来看待。

常见的可重用标准异常

异常使用场合(彼此不一定排斥)
IllegalArgumentException非null的参数值不正确
IllegalStateException不适合方法调用的对象状态
NullPointerException在禁止null的情况下参数为null
IndexOutOfBoundsException索引参数值越界
ConcurrentModificationException在禁止并发修改的情况下,检测到对象被并非修改
UnsupportedOperationException对象不支持用户请求的方法

其他标准异常也可以使用,如ArithmeticException、NumberFormatException。

可以继承标准异常定义新的异常。

记住异常时可序列化的。

重用现有的标准异常,一定要符合异常文档中描述的条件,建立在语义而非名字基础上使用。

Item 73: Throw exceptioons appropriate to the abstraction

抛出与抽象对应的异常

异常转译(exception translation):高层实现捕获低层异常,同时抛出在高层实现中可以解释的异常。换句话说,就是不要直接抛出低层异常,应该根据调用层的实际情况,对低层异常进行处理和转换,再抛出。

异常链:大多数标准的异常都有支持链(chaining-aware)的构造器,可通过getCause()访问原因。对于没有支持链的异常,可调用Throable的initCause()实现。

// 含支持链chaining-aware构造器的异常
class HigherLevelExcetpion extends Exception {
    HigherLevelExcetpion(Throwable cause) {
        super(cause);
    }
}

异常处理步骤:

  1. 首先,尽量避免低层方法抛出异常,如将参数传递给低层方法前校验高层方法参数的有效性。
  2. 其次,当低层异常发生时,最佳做法是在高层将低层异常处理好,避免低层问题和高层函数混杂在一起。并做好日志记录,这允许调查问题同时,将客户端代码和用户从异常问题中隔离出来。
  3. 最后,当无法处理异常时,向上抛出:如果低层异常保证其异常适用于所有高层调用,则可以直接抛出,否则使用异常转译。

Item 74: Document all exceptions thrown by each method

每个方法抛出的所有异常都要建立文档

用@throws标签记录每个异常,并记下抛出每个异常的条件。

如果一个类中多个方法由于相同原因抛出同一个异常,可在类(而非方法)的注释中记录异常。

 Item 75: Include failure-capture information in detail messages

在消息细节中包含失败-捕获信息

  • 异常应该捕获失败信息,供后续分析。
  • 失败信息应包含所有相关参数和域的值,但也应尽量精简。
  • 失败信息中应注意安全敏感信息的保密性,如密码、秘钥。

应在构造器(而不是字符串细节信息)中引入失败-捕获信息:

// 在构造器中引入失败-捕获信息
public IndexOutOfBoundsExceptions(int lowerBound, int upperBound, int index) {
    super(String.format("Lower bound: %d, Upper bound: %d, Index: %d", 
    lowerBound, upperBound, index));
    ... ...
}

Item 76: Strive for failure atomicity

努力使失败保持原子性

失败原子性:失败的方法调用应使对象保持调用前的状态。

实现失败原子性的方法:

  1. 设计并采用immutable不可变对象。
  2. 在执行操作之前检查参数的有效性,使得在对象的状态被修改前,抛出大多数异常。或者,调整计算处理顺序,将修改对象状态的操作放在可能导致失败原子的计算后面。
  3. 在执行操作前对对象进行深度拷贝(将数据拷贝到临时数据结构中还可能提高性能,如有些排序算法在排序前,将数据拷贝到一个数组中,以便降低在排序的内循环中访问元素所需要的开销)。
  4. 增加一段恢复代码(recovery code),拦截失败情况并使对象回滚到初始状态。此方法不常用,主要用于永久性(基于磁盘)的数据结构。

执行操作前未检查导致对象状态被修改的示例:

public Object pop() {
    // if(size == 0)    throw new EmptyStackException();  // 取消此注释可解决问题
    Object result = elements[--size];  // 抛出异常后,size会变为负数
    ... ...
}

实现失败原子的弊端:可能会显著增加开销或者复杂性。

抛出异常的地方都应尽可能保持失败原子性,如果做不到,API文档中应清楚地指出对象会处于增氧的状态。

Item  77: Don't ignore exception

不要忽略异常

不要使用空的catch块,如果选择忽略异常,catch块中应包含一条注释,说明为啥可以这么做,并且变量名应命名为ignore:

try {
    ...
} catch (TimeoutException ignore) {
    // (不用处理该异常的理由)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MOOC(大规模开放式在线课程)是一种通过网络平台开设的在线教育课程,可以为广大学习者提供方便灵活的学习机会。人工智能实践:TensorFlow笔记,是由北京大学推出的一门针对人工智能领域的实践课程,旨在帮助学习者掌握使用TensorFlow框架进行深度学习的基本方法和技巧。 该课程的代码提供了一系列丰富的示例和实践项目,通过这些代码我们可以了解和掌握TensorFlow的使用方法。其中包括数据处理、模型构建、模型训练与评估等关键步骤。通过学习和实践,我们可以学会如何搭建神经网络模型,进行图像分类、文本生成等任务。 在这门课程中,北京大学的代码示例主要围绕深度学习的常用库TensorFlow展开,通过给出具体的代码实现,解释了每部分的原理和操作方法,帮助学习者理解基本概念和技术,熟悉TensorFlow框架和编程语言的使用。 此外,这门课程还涵盖了一些实践项目,例如基于TensorFlow的手写数字识别、图像分类与预测、文本生成等。通过完成这些实践项目,我们可以加深对TensorFlow的理解并提高实践能力。 总之,人工智能实践: TensorFlow笔记 - 北京大学代码是一门结合了理论与实践的在线课程,通过教授深度学习的基本概念和TensorFlow的应用方法,帮助学习者掌握人工智能领域的基本技能。通过这门课程,我们可以学习到TensorFlow的使用方法,掌握一定的实践能力,并将这些知识应用于实际项目当中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值