第12章通过异常处理错误

12.1概念
1、使用异常能够降低错误处理代码的复杂度。
12.2基本异常
1、异常情况是指阻止当前方法或作用域继续执行的问题。把异常情形与普通问题相区分很重要,所谓的普通问题是指,在当前环境下能得到足够的信息,总能处理这个错误。对于异常情形,就不能继续下去了,因为在当前环境下无法获得必要的信息来解决问题。
2、异常允许强制程序停止运行,并告诉出现什么了什么问题,或者(理想状态下)强制程序处理问题,并返回到稳定状态
12.2.1 异常参数
1、所有标准异常类都有两个构造器:一个是默认构造器;另一个是接受字符串作为参数,以便能把相关信息放入异常对象的构造器。
2、Throwable对象,是异常类型的根类。对于不同类型的错误,要抛出相应的异常。错误信息可以保存在异常对象内部或者用异常类的名称来表示。上一次环境通过这些信息来决定如何处理异常。
12.3捕获异常
12.3.1try块
1、对于不支持异常处理的程序语言,要想仔细检查错误,就得在每个方法调用的前后加上设置和错误检查的代码,甚至在每次调用同一个方法时也得这么做。
12.3.2异常处理程序
1、Java支持终止模型。在这种模型中,将假设错误非常关键,以至于程序无法返回到异常发生的地方继续执行。一旦异常被抛出,就表明错误已无法挽回,也不能回来继续执行。
2、Java支持恢复模型。意思是异常处理程序的工作是修正错误,然后重新尝试调用出问题的方法,并认为第二次能成功。
12.4创建自定义异常
12.4.1异常与记录日志
12.5异常说明
1、Java提供了响应的语法(并强制使用这个语法),可以告知客户端程序员某个方法可能会抛出的异常模型,然后客户端程序员就可以进行相应的处理。这就是异常说明,它属于方法声明的一部分,紧跟在形式参数列表之后。
2、可以声明方法将抛出异常,实际上却不抛出。编译器相信了这个声明,并强制此方法的用户像真的抛出异常那样使用这个方法。这样做的好处是:为异常先占个位子,以后就可以抛出这种异常而不用修改已有的代码。在定义抽象基类和接口时这种能力很重要,这样派生类或接口实现就能够抛出这些预先声明的异常。
3、在编译时被强制检查的异常称为被检查的异常。
12.6捕获所有异常
1、可以只写一个异常处理程序来捕获所有类型的异常。通过捕获异常类型的基类Exception,就可以做到这一点。
12.6.1 栈轨迹
1、printStackTrace()方法所提供的信息可以通过getStackTrace()方法来直接访问,这个方法将返回一个由栈估计中的元素所构成的数组,其中每一个元素都表示栈中的一帧。
12.6.2重新抛出异常
1、希望把刚捕获的异常重新抛出,尤其是在使用Exception捕获所有异常的时候。既然已经得到了对当前异常对象的引用,可以直接把它抛出。
2、重抛异常会把异常抛给上一级环境中的异常处理程序,同一个try块的后续catch子句将被忽略。
3、异常对象的所有信息都得以保持,所以高一级环境中捕获此异常的处理程序可以从这个异常对象中得到所有信息。
12.6.3异常链
1、在捕获一个异常后抛出另一个异常,并且希望把原始异常的信息保存下来,就被称为异常链。
2、在Throwable的子类中,只有三种基本的异常类提供了带有cause参数的构造器,它们是Error、Exception以及RuntimeException。如果要把其他类型的异常链接起来,应该使用initCause()方法而不是构造器。
12.7 Java标准异常
1、Throwable这个Java类被用来表示任何可以作为异常被抛出的类。Throwable对象可分为两种类型(指从Throwable继承而得到的类型):Error用来表示编译时和系统错误;Exception是可以被抛出的基本类型,在Java类库,用户方法以及运行时故障中都可能抛出Exception型异常。
12.7.1特例:RuntimeException
1、属于运行时异常的类型有很多,它们会自动被Java虚拟机抛出,所以不必在异常说明中把它们列出来。这些异常都是从RuntimeException类继承而来,所以既体现了继承的优点,使用起来也很方便。这构成了一组具有相同特征和行为的异常类型。并且也不需要在异常说明中声明方法将抛出RuntimeException类型的异常(或者任何从RuntimeException继承的异常),它们也被称为“不受查异常”。这种异常属于错误,将被自动捕获。
2、RuntimeException代表的是编程错误:
①无法预料的错误。比如从你控制范围之外传递进来的null引用。
②作为程序员,应该在代码中进行检查的错误(比如对于ArrayIndexOutOfBoundsException,就得注意一下数组的大小了。)在一个地方发生的异常,常常会在另一个地方导致错误。
12.8.1finally用来做什么
1、当要把除内存之外的资源恢复到它们的初始状态时,就要用到finally子句。
12.8.2 在return中使用finally
1、finally子句总是会执行的,所以在一个方法中,可以从多个点返回,并且可以保证重要的清理工作仍旧会执行。
12.8.3缺憾:异常丢失
12.9异常的限制
1、当覆盖方法的时候,只能抛出在基类方法的异常说明里列出的那些异常。这个限制很有用,因为这意味着,当基类使用的代码应用到其派生类对象的时候,一样能够工作,异常也不例外。
2、异常限制对构造器不起作用,因为基类构造器必须以这样或那样的方式被调用(这样默认构造器将自动被调用),派生类构造器的异常说明必须包含基类构造器的异常说明。
3、派生类构造器不能捕获基类构造器抛出的异常。
4、一个出现在基类方法的异常说明中的异常,不一定会出现在派生类方法的异常说明里。在继承中,基类的方法必须出现在派生类里,换句话说,在继承和覆盖的过程中,某个特定方法的“异常说明的接口”不是变大了而是变小了—-和类接口在继承时的情形相反。
12.10构造器
1、在设计异常时有一个问题:应该把异常全部放在这一层处理;还是先处理一部分,然后再向上层抛出相同的(或新的)异常;又或者是不做任何处理直接向上层抛出。如果用法恰当的话,直接向上层抛出的的确能简化编程。
12.11异常匹配
1、抛出异常的时候,异常处理系统会按照代码的书写顺序找出“最近”的处理程序。找出匹配的处理程序之后,它就认为异常将得到处理,然后就不再继续查找。
2、查找的时候并不要求抛出的异常同处理程序所声明的异常完全匹配。派生类的对象也可以匹配其基类的处理程序。
12.12其他可选方式
1、异常代表了当前方法不能继续执行的情况。开发异常处理系统的原因是,如果为每个方法所有可能发生的错误都进行处理的话,任务就显得过于繁重了。开发异常处理的初衷是为了方便程序员处理错误。
12.12.1历史
12.12.2观点
12.12.3把异常传递给控制台
12.12.4把“被检查的异常”转换为“不检查的异常”
12.13异常使用指南
应该在下列情况下使用异常:
①在恰当的级别处理问题。
②解决问题并且重新调用产生异常的方法。
③进行少许修补,然后绕过异常发生的地方继续执行。
④用别的数据进行计算,以代替方法预计会返回的值。
⑤把当前运行环境下能做的事情尽量做完,然后把相同的异常重抛到更高层。
⑥把当前运行环境下能做的事情尽量做完,然后把不同的异常抛到更高层。
⑦终止程序。
⑧进行简化。
⑨让类库和程序更安全。

猜你喜欢

转载自blog.csdn.net/panda_____/article/details/80287451