一、异常简介
在程序运行过程中,如果环境检测出一个不可以执行的操作,就会出现运行时错误。如果这个错误没有被处理,那么程序将会非正常终止。该如何处理这个异常,以使程序可以继续运行或者平稳终止呢?这就是下面要说到的异常处理。
警告:在这里有必要声明一下,异常处理需要初始化新的异常对象,需要从调用栈返回,而且还需要沿着方法调用链来传播异常以便找到它的异常处理器。所以,异常只有当必须处理不可预料的错误状况时我们才能使用它,不要用try-catch块处理简单的、可预料的情况。比如空指针这些都应该用if来代替。
二、异常类型
下面是Java1.6 API对异常类型的部分截图:
其中,RuntimeException类、Error类以及它们的子类都称为免检异常,所有其它异常都称为必检异常,意思是指编译器会强制程序员检查并处理它们。为避免过多地使用try-catch块,Java语言不允许编写代码捕获或声明免检异常。
1. Throwable类是所有异常类的根。所有的Java异常类都直接或者间接地继承自Throwable。
2. Error类扩展了Throwable类,描述的是内部系统错误,由Java虚拟机抛出,如果发生,除了通知用户以及尽量稳妥地终止程序外,几乎什么也不能做。
3. Exception类也扩展了Throwable类,它描述的是由程序和外部环境所引起的错误,这些错误能被程序捕获和处理。
4. RunTimeException类是Exception类的一个扩展,它描述的是程序设计错误,例如错误的类型转换,数组越界等。运行时异常通常由Java虚拟机抛出。
三、异常处理
1. 声明异常
程序中每个方法都必须声明它可能抛出的必检异常的类型,方法的调用者就必须去捕获该异常,这称为声明异常。语法如下:
public void myMethod() throws Exception1,Exception2{ ... }
如果方法抛出的是免检异常(Error异常和运行时异常)调用者也不会被编译器强制try/catch异常。如果方法在父类中没有声明异常,那么就不能在子类中对其进行覆盖来声明异常。
2. 抛出异常
检测一个错误的程序可以创建一个正确异常类型的实例并抛出它,这时catch()块将接手这个异常。这就称为抛出一个异常。通常,Java API中的每个异常类至少有两个构造方法,一个无参构造方法和一个带有可描述这个异常的String参数的构造方法,如下:
throw new Exception1();
throw new Exception1("message");
3. 捕获异常
当抛出一个异常时,可以在try-catch块中捕获并处理它,如下:
try{
...
}catch(Exception1 e1){
...
}catch(Exception2 e2){
...
}
从第一个到最后一个逐个检查catch块,判断在catch块中的异常类实例是否是该异常对象的类型。如果是,就将该异常对象赋值给所声明的变量,然后执行catch块中代码。如果没有发现异常处理器,Java会退出这个方法,把异常传递给调用这个方法的方法,继续同样的过程来查找处理器。如果在调用的过程中找不到处理器,程序就会终止并且在控制台上打印出错信息。
如果一个catch块可以捕获一个父类的异常对象,它就能捕获那个父类的所有子类的异常对象。注意,如果父类的catch块出现在子类的catch块之前就会导致编译出错。
4. 获取异常信息
Throwable类中提供了一些方法来获取异常对象的有价值的信息,如下:
public String getMessage() //返回这个对象的消息
public String toString() //返回异常类的命名+":"+getMessage()
public void printStackTrace() //在控制台打印Throwable对象以及它的调用栈的跟踪信息
public StackTraceElement[] getStackTrace() //返回栈跟踪构成的数组来表示这个可抛出的栈跟踪信息
5. finally子句
有时候无论异常中否出现或者中否被捕获,都希望执行某些代码,可利用finally子句来达到这个目的。
try{
...
}catch(Exception1 e1){
...
}finally{
...
}
注意,即使在到达finally块之前有一个return语句,finally块还是会执行。
6. 重新抛出异常
如果异常处理器没有处理某异常、或者处理器只是希望它的调用者注意到该异常,Java就允许异常处理器重新抛出该异常,此时调用者的其它处理器就会获得处理此异常的机会。
try{
...
}catch(Exception1 e1){
...
throw e1;
}
7. 链式异常
有时候,可能需要同原始异常一起抛出一个新异常(带有附加信息),这称为链式异常。
try{
...
}catch(Exception1 e1){
...
throw new Exception1("new exception", e1);
}
8. 创建自定义异常类
Java提供了相当多的异常类,尽量使用它们不要创建自己的异常类。如果遇到一个不能用预定义异常类恰当描述的问题,那我们就可以通过派生Exception类或其子类来创建自己的异常类。
- public MyException extends Exception{
- private String value;
- public MyException(String value){
- super("Value:" + value);
- this.value = value;
- }
- public String getValue(){
- return value;
- }
- }
-
- throw new MyException("jiang");