Java中的常用异常处理

来源:互联网 发布:三少爷的剑 知乎 编辑:程序博客网 时间:2024/06/08 08:43

一、Java异常处理机制概述
1、Java虚拟机用方法调用栈来跟踪每个线程中一系列的方法调用过程。
2、方法中的代码块可能抛出异常,有如下两种处理办法:
l 在当前方法中通过try…catch语句捕获并处理异常。例如:

public void methodA(intmoney){try{//以下代码可能会抛出SpecialExceptionif(--money <= 0)throw new SpecialException("Out of money");}catch(SpecialExceptione){//异常处理}}

l 在方法的声明处通过throws语句声明抛出异常,返回给调用者来处理异常例如:
由于方法A不能捕获异常,所以,A就要通过throws语句声明抛出异常,由调用者methodB()来处理异常

public void methodA(intmoney) throws SpecialException{//以下代码会抛出SpecialExceptionif(--money <= 0)throw new SpecialException("Out of money");}此时methodB()的定义如下:public void methodB(intmoney){try{methodA(money);}catch(SpecialExceptione){//处理异常}}

如果methodB()也没有捕获SpecialException,而是声明抛出该异常,则Java虚拟机的处理流程将退回到methodB()方法的调用者,此时methonB()方法的定义如下:
publicvoidmethodB(intmoney)throwsSpecialException{
methodA(money);
}
3、当Java虚拟机追溯到调用栈的底部的方法时,如果仍然没有找到处理该异常的代码块,将按以下步骤处理:
l 调用异常对象的printStackTrace()方法,打印来自方法调用栈的异常信息。
l 如果该线程不是主线程,那么终止这个线程,其他线程继续正常运行。如果该线程是主线程(即方法调用栈的底部为main()方法),那么整个应用程序被终止。

二、运用Java异常处理机制
1、在Java语言中,用try…catch语句来捕获异常,格式如下:

try{//可能会出现异常的代码}catch(SQLExceptione){//处理操纵数据库出现的异常}catch(IOExceptione){//处理操纵输入流和输出流出现的异常}

2、finally语句中的代码是在异常处理的任何情况下都必须执行的代码。finally代码块能保证特定的操作总是会被执行,它的形式如下:

try{//可能会出现异常的代码}catch(Exceptione){//处理异常}finally{//特定的操作}

3、不管try代码块中是否出现异常,都会执行finally代码块。
4、如果一个可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常。一个方法可能会出现多种异常,throws子句允许声明抛出多个异常,例如:
public void method() throws SQLException,IOException{…}
5、throw语句用于抛出异常,由throw语句抛出的对象必须是java.lang.Throwable类或者其子类的实例。
6、异常处理语句的语法规则:
l try代码块不能脱离catch代码块或finally代码块而单独存在。try代码块后面至少有一个catch代码块或finally代码块。
l try代码块后面可以有零个或多个catch代码块,还可以有零个或至多一个finally代码块。如果catch代码块和finally代码块并在,finally代码块必须在catch代码块后面。
l try代码块后面可以只跟finally代码块。
l 在try代码块中定义的变量的作用域为try代码块,在catch代码块和finally代码块中不能访问该变量。
l 当try代码块后面有多个catch代码块时,Java虚拟机会把实际抛出的异常对象依次和各个catch代码块声明的异常类型匹配,如果异常对象为某个异常类型或其子类的实例,就执行这个catch代码块,而不会再执行其他的catch代码块。
l 如果一个检查异常,要么用try…catch语句捕获,要么用throws语句声明将它抛出,否则会导致编译错误。
l throws语句后面不允许紧跟其他语句,因为这些语句永远不会被执行。
7、异常流程的运行过程:
l finally语句不会被执行的惟一情况是先执行了用于终止程序的System.exit()方法。exit()方法的定义如下:public static void exit(int status) ,exit()方法的参数status表示程序终止时的状态码,按照编程惯例,0表示正常终止,非零数字表示异常终止。
l return语句用于退出本方法。在执行try或catch代码块中的return语句时,假如有finally代码块,会先执行finally代码块。
l finally代码块虽然在return语句之前被执行,但finally代码块不能通过重新给变量赋值的方式来改变return语句的返回值。
l 建议不要在finally代码块中使用return语句,因为它会导致两种潜在的错误。第一种错误是覆盖try或catch代码块的return语句,第二种错误是丢失异常。

三、Java异常类
1、所有异常类的祖先类为java.lang.Throwable类,它的实例表示具体的异常对象,可以通过throw语句抛出,Throwable类提供了访问异常信息的一些方法,常用的方法包括:
l getMessage()——返回String类型的异常信息。
l printStackTrace()——打印跟踪方法调用栈而获得的详细异常信息。在程序调试阶段,此方法可用于跟踪错误 。
2、常见的运行时异常包括:NullPointerException、ClassCastException、ArithmeticException、IllegalArgumentException和IndexOutOfBoundsException,这种异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常时,即使没有用try…catch语句捕获它,也没有用throws子句声明它,还是会通过编译。

四、异常处理原则
1、异常处理只能用于非正常情况。
2、为异常提供说明文档。通过JavaDoc的@throws标签来描述产生异常的条件。
3、尽可能地避免异常。
4、保持异常的原子性。异常的原子性是指当异常发生时后,各个对象的状态能够恢复到异常发生前的初始状态,而不至于停留在某个不合理的中间状态。保持原子性有以下办法:
l 最常见的办法是先检查方法的参数是否有效,确保当异常发生时还没有改变对象的初始状态。
l 编写一段恢复代码,由它来解释操作过程中发生的失败,并且使对象状态回滚到初始状态。这种办法不是很常用,主要用于永久性的数据结构,比如数据库系统的回滚机制就采用了这种办法。
l 在对象的临时拷贝上进行操作,当操作成功后,把临时拷贝中的内容复制到原来的对象中。
5、避免过于庞大的try代码块。
6、在catch子句中指定具体的异常类型
7、不要在catch代码块中忽略被捕获的异常。

五、常见问题和注意事项
1 、 注意:
A:子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏了,儿子不能比父亲更坏)
B:如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常
C:如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws
上述仅仅针对编译时期异常
与运行时期异常无关。

2、throw和throws的区别?
throws:
用在方法声明后面,跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,并不一定会发生这些异常
throw:
用在方法体内,跟的是异常对象名
只能抛出一个异常对象名
表示抛出异常,由方法体内的语句处理
throw则是抛出了异常,执行throw则一定抛出了某种异常?
注意:
1. 如果throw的是编译时期异常,在方法声明上必须用throws进行标记
2. 如果throw的是运行时期异常,在方法声明上可以用throws进行标记,也可以不用。

0 0
原创粉丝点击