5 分钟掌握 Java核心之四:异常处理三原则

问题

在开始本文之前,尝试回答如下问题

  1. NoClassDefFoundError 和 ClassNotFoundException 有什么区别
  2. 什么是 checked exception 怎么看?
  3. 什么异常不应该捕获?什么时候抛出异常( throw),什么时候声明抛出异常( throws),什么时候捕获之后重新抛出?
  4. try with resurce、try catch finally,multiple catch 分别指什么?用在什么场景?
  5. 捕获异常要注意的地方
  6. 异常日志如何记录,应不应该打印堆栈
  7. 异常处理最佳实践:全局异常避免堆栈暴露
  8. 什么是异常控制流程,举例说明
  9. 哪些异常不需要捕获,哪些异常要捕获,例外情况是什么?
  10. 哪些是敏感异常,敏感异常如何处理
  11. 你所在的团队是否有异常处理规范
  12. 异常的性能问题及原理
  13. 多线程下的异常处理?对于线程池注意Runntimeexception导致的线程逃逸现象。UnCaughtExceptionHandler
  14. 不同编程范式下的异常处理,反应式编程,lambda/stream

目标

掌握 Java 异常

为什么需要异常

如果没有异常,我们需要在每个函数都判断成功或失败,有了异常,只需要在出现错误对方抛出,在可以处理异常的地方捕获异常即可。代码明显比用错误码的方式要简洁很多。写过 C, Go 的应该都深有体会。比如 go 2.0 已经计划引入异常便是最好的明证。

异常提供了一种识别及响应错误情况的一致性机制,有效地异常处理能使程序更加健壮、易于调试。

异常之所以是一种强大的调试手段,在于其回答了以下三个问题:

  • 什么出了错
  • 在哪出的错
  • 为什么出错

在有效使用异常的情况下,异常类型回答了“什么”被抛出,异常堆栈跟踪回答了“在哪”抛出,异常信息回答了“为什么”会抛出,如果你的异常没有回答以上全部问题,那么可能你没有很好地使用它们。

异常处理原则

有三个原则可以帮助你在调试过程中最大限度地使用好异常,这三个原则是:

  • 具体明确
  • 提早抛出(throw early)
  • 延迟捕获(catch late)
具体明确

Java 定义了一个异常类的层次结构,其以 Throwable 开始,扩展出 Error 和 Exception,而 Exception
又扩展出 RuntimeException。

这四个类是泛化的,并没有提供多少出错信息,虽然实例化这几个类是语法上合法的(如 new Throwable()), 但是最好还是把它们当虚基类看,使用它们的子类。Java 已经提供了大量异常子类,如需更加具体,你也可以定义自己的异常类。

java.io 包中定义了 Exception 类的子类 IOException,IOException 包括更加具体如 FileNotFoundException、EOFException、SocketException、 ObjectStreamException 等子类。每一种都描述了一类特定的I/O 异常。异常越具体,我们的程序就能更好地回答“什么出了错”这个问题。

提早抛出

异常堆栈信息提供了异常调用链的精确顺序,包括。详细记录了什么出了错(提供了非法参数值)、为什么出错(比如文件名不能为空值)、以及哪里出的错(每个方法调用的类名,方法名,文件名甚至行数),以此来精确定位异常现场。
通过在检测到错误时立刻抛出异常(迅速失败),可以有效避免不必要的对象构造或资源占用。比如文件或网络连接资源,同样,打开这些资源所带来的清理操作也可以省略。比如

public test(String fileName) {
	if (isVaildFileName(fileName)) {
    throw new IllegalArgumentException("file is not vaild");
  }
  //创建资源
  //IO 操作
}

这里将文件名的判断提前,而不是在打开资源的之后,在具体执行操作的时候才处理。

延迟捕获

异常的处理中非常容易犯的一个错误是:在程序有能力处理异常之前就捕获它。出现异常自然而然的做法就是立即将代码用try块包装起来,并使用catch捕获异常,以免编译器报错。Java 中检查
异常必须被捕获或抛出助长了这种错误行为。

问题在于,捕获之后该拿异常怎么办?最不该做的就是什么都不做。空的 catch 块等于把整个异常丢进黑洞,能够说明何时何处为何出错的所有信息都会永远丢失。把异常写到日志中还稍微好点,至少还有记录可查。但我们总不能指望用户去阅读或者理解日志文件和异常信息。

捕获异常之后处理的标准:

  1. 如果你的方法无法胜任,那么就不要处理异常,把它留到后面捕获和在恰当的层面处理。
  2. 在合适的层面捕获异常,以便你的程序要么可以从异常中有意义地恢复并继续下去,而不会导致更深入的错误。
  3. 为用户提供明确的信息,包括引导他们从错误中恢复过来。

总之,一句话,如果你不知道怎么处理,就不要处理

结论

经验丰富的开发人员都知道,调试程序的最大难点不在于修复缺陷,而在于从海量的代码中找出缺陷的藏身之处。只要遵循本文的三个原则,就能让你的异常协助你跟踪和消灭缺陷,使你的程序更加健壮,对用户更加友好。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值