异常
什么是异常
异常是程序中的一些错误,在Java中引入了异常,以异常类的形式对这些非正常情况进行封装,通过异常处理机制对程序运行时发生的各种问题进行处理。通过以下一个案例认识一下什么是异常
算数异常从运行结果可以看出,程序发生了算数异常(ArithmeticException),这个异常是由于第三行中代码调用divide()方法时传入了参数0,而在divide()方法中,运算时出现了被0除的情况。在这个异常发生后,程序会立即结束,无法继续往下执行。
java.lang.Throwable类分类ArithmeticException异常只是Java异常类中的一种,在Java中还提供了大量的异常类,这些类都继承自java.lang.Throwable类。
Java.lang.throwable类有两个直接子类:Error和Exception
Error代表程序中产生的错误,Exception代表程序中产生的异常
Error类称为错误类,它表示java运行时产生的系统内部错误或资源耗尽的错误,是比较严重的,仅靠修改程序本身是不能恢复执行的。
Exception类称为异常类,它表示程序本身可以处理的错误。在开发Java程序中进行的异常处理都是针对Exception类及其子类。在Exception类中众多的子类中有一个特殊的RuntimeException,该类及其子类用于表示运行时异常。除了此类,Exception类下所有其他的子类都用于表示编译时异常。
try…catch和finally
在上面的代码中,由于发生了异常导致程序立即终止,所以无法继续向下执行了。为了解决这样的问题,Java中提供了一种对异常进行处理的方式——异常捕获。异常捕获通常使用try——catch语句。
try{
//程序代码块
}catch(ExceptionType(Exception类及其子类)e){
//对Exception的处理
}
其中,在try代码块中编写可能发生异常的Java语句,catch代码块中编写针对异常进行处理的代码。当try代码块中的程序发生了异常,系统会将这个异常的信息封装成一个异常对象,并将这个对象传递给catch代码块。catch代码块需要一个参数指明它所能够接收的异常类型,这个类型的参数必须是Exception类或子类。
上面的代码对可能发生异常的代码用try…catch语句进行了处理。在try代码块中发生被0除异常时,程序会转而执行catch中的代码,通过调用Exception对象的getMessage()方法,返回异常信息“/by zero”。catch代码块对异常处理完毕后,程序仍会向下执行,而不会异常终止。
在程序中,有时候我们会希望有些语句无论程序是否发生异常都要执行,这时就可以在try…catch语句后加一个finally代码块。
在catch代码块中增加了一个return语句,用于结束当前方法,此时程序第12行就不会再执行了,而finally代码仍会执行,并不会被return语句所影响。也就是说,不论程序是发生异常还是使用return语句结束,finally中的语句都会执行。正是由于这种特殊性,在程序设计时,经常会在try…catch后使用finall代码块来完成必须做的事,例如释放系统资源。
需要注意的时、是,finally的代码块在一种情况下是不会执行的,那就是在try…catch中执行了System.exit(0)语句。System.exit(0)表示退出当前Java虚拟机,Java虚拟机停止了,任何代码都不能执行了。
throws关键字
在上面的代码中调用的是自己写的divide()方法,因此很清楚方法可能会发生异常。但如果去调用别人写的一个方法时,是否能直到别人的方法是否有异常呢?这是很难做出判断的。针对这种情况,Java中允许在方法的后面使用throws关键字对外声明有可能发生的异常,这样调用者在调用方法时,就明确地知道该方法有异常,并且必须在程序中对异常进行处理,否则编译无法通过。
throws关键字声明抛出异常的语法格式如下。
throws关键字抛出异常 抛出并捕获异常 抛出后继续抛出异常修饰符 返回值类型 方法名 ( [ 参数1,参数2…… ] )throws ExceptionType1[
,Exception Type2……]{
}
以上代码得出的结论:
抛出异常后调用者就必须进行处理,否则会发生编译错误
如果不知道如何处理声明抛出的异常,也可以使用throws关键字继续讲异常抛出,这样程序也能编译通过。但需要注意的是,程序一旦发生异常,如果没有被处理,程序就会非正常终止。
编译时异常与运行时异常
在程序编译时产生的一些异常称为编译时异常,也称为checked异常。另外还有一种异常时运行时产生的,这种异常即使不编写异常处理代码,依然可以通过编译,因此被称为运行时异常也称为unchecked异常。
编译时异常:编译时异常的特点是Java编译器会对其进行检查,如果出现异常就必须对异常进行处理,否则程序无法通过编译。
处理编译时异常有两种方法:
1)使用try…catch语句对异常进行捕获
2)使用throws关键字声明抛出异常,调用者对其处理
运行时异常:Java编译器不会对其进行检查,也就是说程序中出现这类异常时,即使没有用try…catch语句捕获或使用throws关键字抛出,程序也能编译通过。运行时异常一般是由程序中的逻辑错误引起的,在程序运行时无法恢复。例如通过数组角标访问数组元素时,如果超过了数组的最大角标,就会发生运行时异常,出现ArrayIndexOutOfBoundsException异常。
自定义异常
Java允许用户用户自定义异常。
如果希望写一个检查性异常类,则需要继承 Exception 类。
如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。
既然自定义了异常,那么该如何使用呢?这时候就需要用到throw关键字,throw关键字用于在方法中声明抛出异常的实例对象,其语法结构如下。
throws Exception 异常对象
上面的程序在编译时就发生了异常。这是因为在一个方法内使用throw关键字抛出异常对象时,需要使用try…catch语句对抛出的异常进行处理,或者在divide()方法上使用throws关键字声明抛出异常由该方法的调用者处理。