异常
一、Error和Exception
Throwable是Java语言中所有错误和异常的超类。它有两个子类:Error和Exception。
- Error:是程序无法处理的错误,表示运行应用程序中较严重的问题。Error类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。
- Exception是程序可以处理的异常。它又主要包括两个分支:一个分支派生于RuntimeException(又称为uncheckedException),另一分支包含其他异常(又称为CheckedException)。划分的规则:由程序错误导致的异常属于RuntimeException。程序本身没有问题,但由于像I/O错误这类问题导致的异常属于其他异常。
二、RuntimeException和CheckedException
派生于RuntimeException的异常包含下面几种情况:
- 错误的类型转换
- 数组访问越界
- 访问空指针
对于运行时异常,程序可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类错误。有一条规则“如果出现RuntimeException异常,那么就一定是你的问题。”它的特点是Java编译器不会检查它,即使没有抛出也没有try-catch捕获也可以编译通过。
a. 指的是程序的瑕疵或逻辑错误,并且在运行时无法恢复。
b. 包括Error与RuntimeException及其子类,如:OutOfMemoryError, UndeclaredThrowableException, IllegalArgumentException, IllegalMonitorStateException, NullPointerException, IllegalStateException, IndexOutOfBoundsException等。
c. 语法上不需要声明抛出异常。
不是派生于RuntimeException的异常包括:
- 试图在文件尾部后面读取数据
- 试图打开一个不存在的文件
- 试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在
a. 代表程序不能直接控制的无效外界情况(如用户输入,数据库问题,网络异常,文件丢失等)
b. 除了Error和RuntimeException及其子类之外,如:ClassNotFoundException, NamingException, ServletException, SQLException, IOException等。
c.非运行时异常是必须进行处理的异常, 需要try catch处理或throws声明抛出异常。如果不处理,程序就不能编译通过。
三、异常声明
异常声明即通过throws语句,在方法名和参数后用throws声明,可以throws多个异常,用逗号隔开。例如:
public Image loadImage(String s) throws FileNotFindException,EOFException
四、抛出异常
当一个方法出现错误引发异常时,方法创建异常对象并交付运行时系统,异常对象中包含了异常类型和异常出现时的程序状态等异常信息。运行时系统负责寻找处置异常的代码并执行。
if(n < len) throw new EOFException();
对于一个已经存在的异常类,将其抛出非常容易:
- 找到一个合适的异常类
- 创建这个类的一个对象
- 将对象抛出
五、创建异常类
如果任何标准异常类都没有充分描述清楚的问题,可以自己创建一个异常类。定义一个派生于Exception的类,或者派生于Exception子类的类。例如定义一个派生于IOException的类。习惯上,定义的类包含两个构造器,一个是默认的构造器,另一个 是带有详细描述信息的构造器(超类Throwable的toString方法会打印这些详细信息,在调试中非常有用。)
class MyException extends IOException{
pubic MyException()
public MyException( String gripe)
{
super(gripe);
}
}
然后就可以在程序中抛出自定义的异常类型,throw new MyException();
六、捕获异常
捕捉异常:在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适 的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适 的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。
6.1 try/catch语句
如果某个异常发生的时候没有地方进行捕获,那么程序就会终止执行,并在控制台上打印异常信息,包括异常的类型和堆栈的内容。要想捕获一个异常,必须设置try/catch语句块。
try{
语句块
}
catch(ExceptionType e)
{
处理语句块
}
如果try语句块中代码抛出了catch子句中说明的异常类,那么程序将跳过try语句块的其余代码,执行catch子句的处理代码。如果try语句块中没有抛出任何异常,那么程序将跳过catch子句。如果方法中的任何代码抛出了一个在catch子句中没有声明的异常类型,那么方法就会退出。
catch块可以有多个,来捕获多个异常。catch子句中也可以抛出一个异常,改变异常类型。
finally子句
当代码抛出一个异常,会终止方法中剩余代码处理,并退出方法执行。如果方法获得了一个本地资源,在退出方法之前必须被回收,会产生资源回收问题。为了更好的解决这个问题,可以用finally子句。不管是否有异常被捕获,finally子句中的代码都被执行。
七、分析堆栈跟踪元素
堆栈跟踪stack trace是一个方法调用过程的列表。它包含程序执行过程中方法调用的特定位置。可以调用Throwable类的printStackTrace()方法访问堆栈跟踪的文本描述信息。