十二 通过异常处理错误
异常处理的任务就是将程序从错误的状态拯救出来,换一种方式继续运行程序
发现错误的理想时机当然是编译阶段-------程序运行之前。但是理想很丰满现实很骨感,在编译期间并不能找到所有的错误,可是存在问题总得解决而不是一味地带逃避。所以只有在发生错误的时候将错误源通过某种方式用适当的形式传递给接收者,让其知道如何处理这个问题。
使用异常能够降低错误处理代码的复杂度。如果不用异常,就得在许多地方去处理错误。而且异常处理程序中,可以把“描述执行过程做什么”的代码和“出问题怎么办”的代码分割,是的整个异常处理逻辑阅读、编写、调试都清晰易懂。
基本异常
异常:是指阻止当前方法或作用域继续执行的问题。(在当前环境下没有足够的信息支撑解决的问题)
普通问题:在当前环境下能得到足够信息,就能解决的错误
异常抛出:把异常和普通问题区分很重要,当前环境下无法获得必要的信息来解决此问题。只能从当前环境下跳出,并把问题交给上级环境的动作。
举一个简单的栗子,int i,t; i/t; t可能为0 ,这个检查就很有必要。但除数为0代表的究竟是代表什么意思?如果在当前环境下不知如何处理!何不异常抛出。这里要说一下异常抛出后随之发生的几个事件:
- new 异常对象
- 代码当前执行路径终止,抛出异常对象引用
- 异常处理机制接管程序,然后寻求适当的地方继续执行程序
如上操作就是异常处理的任务就是将程序从错误的状态拯救出来,换一种方式继续运行程序 实现该功能的基础步骤,与使用Java其他对象一样,我们总是new 创建异常对象,当然这也伴随这储存空间的分配和构造器的调用。所有的异常类都分为两类constructor:默认构造器;接受字符串作为参数,一遍把相关信息放入异常的构造器。
if (list == null) {
throw new NullPointerException();
throw new Exception("t == null");
}
能够抛出任意类型的Throwable对象,他是异常类型的根类。对于不同类型的异常情形,故要抛出相应的异常!当然错误信息可以保存该类异常类的名称,上一层环境由此信息来决定如何处理该异常。
捕获异常和异常处理
要理解异常是如何捕获,就先要理解监控区域(guarded region),它是一段可能产生异常的代码,其后跟着处理异常的代码。如
try {
// 可能产生异常的代码(监控区域)
} catch(Type1 id1) {
// 处理异常Type1 的代码
} catch(Type2 id2) {
//处理异常Type2 的代码
}
如此每个抛出的异常Type1、Type2 都必须在某处得到处理。catch(){处理块} 则是异常处理程序,每个异常处理程序如同一个接收有且只有一个特殊类型(如上标识符id1、id2)的参数方法。
创建自定义异常
对于无法表示的程序所遇到的特定问题可以通过自定义异常类解决。
创建新的异常类最好是在现有的异常类的基础上,选择意思相近的异常类继承,以此来达到为我们产生默认构造器,减少代码量。
简单的异常继承:public class MyException extends Exception {}
结果如下:
当然System.out.println(" 处理MyException的程序块")替换为System.out.err(" 处理MyException的程序块");效果更好。
前者会被重定向,后者则不会。更容易硬气用户的注意。
为异常类定义一个接受字符串的参数构造器MyExceptin(String msg),使用super关键字明确调用了其基类构造器使其能够接受一个字符串作为参数。
调用了Throwable声明的printStackTrace()方法。该信息将被输出至标准错误流。
异常层次结构
Throwable 这个Java类被用来表示任何可以作为异常被抛出的类。他可以分为两类:
1.Error:该类和其子类表示系统中的内部错误以及资源耗尽的错误,一般比较严重。
2.Exception 是可以抛出的基本类型。一般分为RuntimeException 和其他非RuntimeException。