概述

Java的基本理念是“结构不佳的代码不能运行”。

本文解决的问题

  • 什么是异常?
  • 为什么需要提供异常机制?异常机制的作用
  • Java异常实现时,有哪些方面的考虑?
  • 异常的概览
  • 异常的分类
  • 异常是如何输出到日志的

什么是异常?

异常是指在程序运行过程中发生的异常事件,通常是由于外部问题(如硬件、输入错误)锁导致的。

“异常”这个词有“我对此感到意外”的意思。问题出现了,你也许不清楚该如何处理,但你的确知道不应该置之不理;你要停下来,看看是不是有别人活在别的地方,能够处理这个问题。只是在当前的环境中没有足够的信息来解决这个问题,所以把这个问题提交到一个更高级别的环境中,在这里将作出正确的决定。

©《Java编程思想(第四版)》

为什么要提供异常机制?异常机制的作用

  • Java需要某种方式,当程序运行发生错误时,它应该通过某种方式,把适当的信息传递给某个接受者——该接收者将指导如何正确处理这个问题。

    发现错误的理想时机是在编译阶段,也就是在你试图运行程序前。然而,编译期间并不能找出所有的错误,余下的问题必须在运行期间解决。这就需要当程序运行发生错误时,它应该通过某种方式,把适当的信息传递给某个接受者——该接收者将指导如何正确处理这个问题。

    改进的错误恢复机制是提供代码健壮性的最强有力的方式。错误恢复在我们所编写的每一个程序中都是基本的要素,但是在Java中它显得格外重要,因为Java的主要目标之一就是创建供他人使用的程序构件。要创建健壮的的系统,它的每一个构件都必须是健壮的。Java使用异常来提供一致的错误报告模型,使得构件能够与客户端代码可靠地沟通问题。

    Java中的异常处理的目的在于通过*使用少于目前数量的代码来简化大型、可靠地程序的生成,并且通过这种方式可以使你更自信:你的应用中没有未处理的错误。

    ©《Java编程思想(第四版)》

  • C以及其他早期语言由于缺乏语言级别的错误处理。程序员通常会忽略错误检查,这对于构造大型、健壮、可维护的程序而言,这种错误处理模式已经成为主要的障碍。Java通过语言级别的强制规定来强制程序员来处理程序中可能出现的异常。

  • 可以降低错误处理的复杂度,明确什么时候应该进行错误处理;将处理错误的代码与程序正常的处理逻辑相分开,是程序更有条理。

  • 开发异常处理系统的原因是,如果为每个方法所有可能发生的错误都进行处理的话,任务就显得过于繁重了,程序员也不愿意这么做。结果常常是将错误忽略。应该注意到,开发异常处理的初衷是为了方便程序员处理错误。

异常概览

异常分为意料之中的、意料之外的、可以处理的、不可以处理的。

对于意料之中的错误我们

异常处理的两种模型

  • 终止(终止当前操作,并不是程序终止)模型,这种模型中假设错误非常关键,以至于程序无法返回到异常发生的地方继续执行。一旦异常被抛出,就表面错误已经无法挽回,也不能回来继续执行。
  • 恢复(被调用方法自己尝试恢复当前出错的操作,并不是在抛出异常后,让调用者恢复)模型,认为异常处理程序的工作是修正错误,然后重新尝试调用出问题的方法,并任务第二次能成功。对于恢复模型,通常希望异常被处理后程序能够继续执行。

异常的使用

try(
	//在此处创建的对象并且实现了 AutoCloseable 接口,可以自动关闭资源。by JDK 1.7
){
    //可能发生异常的代码逻辑
}catch(){
    //处理异常
}final{
    //恢复数据,或关闭资源
}

创建自定义异常

对异常来说最重要的就是类名提供的信息。Java鼓励人们把方法可能会抛出的异常告知使用此方法的客户端程序员。


Java标准异常

  • Throwable这个Java类被用来表示任何可以作为异常被抛出的类。
  • Error用来表示编译时和系统错误(除特殊情况外,一般不需要关系)
  • Exception是可抛出的异常,在Java类库、用户方法以及运行时故障都可能抛出Exception异常。
  • RuntimeException及其子类属于不受检查异常,将被自动补获,会被Java虚拟机自动抛出,所以不必再异常说明中把它们列出来。

RuntimeException代表编程错误:

  • 无法预料的错误。比如从你控制范围之外传递进来的null引用。
  • 作为程序员,应该在代码中检查错误。(比如对于ArrayIndexOutOfBoundsException,就得注意一下数组的大小了。)在一个地方发生的异常,常常会在另一个地方导致错误。

异常声明

异常声明说明了:

  • 我的代码会产生生这种异常,这由你来处理
  • 我的代码忽略了这个异常,这由你来处理。

final

无论try块中的异常是否抛出,他们都能得到执行。

什么时候使用final

当要把资源恢复到它们的初始状态或者释放资源时。

注意
  • final中发生异常可以覆盖try代码块中的异常。

  • final中无法更改返回值

异常的限制

当覆盖方法时,只能抛出在类方法的异常说明里列出的异常。这个限制很有用,因为这意味着,当基类使用的diamante应用到其派生类对象的时候,一样能工作(当然这是面向对象的基本概念),异常也不例外. ©《Java编程思想(第四版)》

构造器

因为异常的主要是资源恢复,与释放资源,但是因为构造的对象还尚未使用,所有在构造方法中并不能使用final来释放资源。

异常匹配

抛出异常时,异常处理系统会按照代码的书写顺序找出“最近”的处理程序。找到匹配的程序会,它就任务异常得到了处理,然后就不造继续查找。

异常处理的原则

  • 只有在你知道如何处理的情况下才捕获异常。实际上,异常处理的一个重要目标就是把错误处理的代码同同错误发生的地点相分离。这使你能在一段代码中专注于要完成的事情,至于如何处理错误,则放在另一端代码中完成。这样一来,主干代码就不会与错误处理逻辑混在一起,也更容易理解和维护。通过允许一个处理程序处理多个错误点,异常处理还使得错误处理代码的数量趋向与减少。

异常吞食

被检查异常强制你在可能还没有准备好处理错误的时候被迫加上catch子句,这就导致了harmful if swallowed问题。