资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,第,6,章,Java,的异常处理机制,6.1 异常的含义及分类,6.2 异常处理,6.3 两种抛出异常的方式,6.4 自定义异常,6.5 常见异常,6.1,异常的含义及分类,1,异常的含义,所谓异常就是程序运行时可能出现一些错误,,比如试图打开一个根本不存在的文件等,2,异常处理的必要性,传统错误处理的不足之处,主要表现为:(,1,)程序复杂;(,2,)可靠性差;(,3,)返回信息有限;(,4,)返回代码标准化困难。,Java,语言采用错误代码和异常处理相结合的方式可以把错误代码与常规代码分开,也可以在,catch,中传播错误信息,还可以对错误类型分组。,6.1,异常的含义及分类,3异常的分类,在java语言中,异常是一个对象,它继承于Throwable类,所有的Throwable类的子孙类所产生的对象都是例外(异常)。从Throwable直接派生出的异常类有 Exception 和 Error,如图6-1所示。,图,6-1 Java,异常层次图,Throwable,Error,Exception,RuntimeException,ContingencyException,6.1,异常的含义及分类,Exception,是代表了真正实际意义上的异常对象的根基类。,Exception,和从它派生而来的所有异常都是应用程序能够捕获到的,并且可以进行异常错误恢复处理的异常类型。,Error,则表示 出现了一个非常严重的异常错误,并且这个错误可能是应用程序所不能恢复的,例如,LinkageError,,或,ThreadDeath,等。由,Java,虚拟机生成并抛出,,Java,程序不做处理。,和的子类免于编译时的检查。,RuntimeException,异常由系统检测,用户的,Java,程序可不做处理,系统将它们交给缺省的异常处理程序。,6.2,异常处理,6.2.1 异常处理的基本结构,6.2.2 多个catch 块,6.2.3 finally语句,6.2.1,异常处理的基本结构,1,异常处理的定义,异常处理是用户程序以预定的方式响应运行错误和异常的能力。它的基本方式是:当一个方法引发一个异常后,可将异常抛出,由该方法的直接或者间接调用者处理异常。,2,异常处理语句,异常处理语句有,try,、,catch,、,finally,、,throw,和,throws,。在以下部分将逐一介绍这些语句的作用。,6.2.1,异常处理的基本结构,3异常处理的基本结构,try catch结构是异常处理的基本结构。这种结构中可能引发异常的语句封入在try块中,而处理异常的相应语句封入在catch块中。结构的格式如下:,try,程序执行体,catch(异常类型1 异常对象1),异常处理程序体1,6.2.1,异常处理的基本结构,3异常处理的基本结构,catch(异常类型2 异常对象2),异常处理程序体2,catch(异常类型n,异常对象n,),异常处理程序体n,finally,异常处理结束前的执行程序体,/,不论发生什么异常(或者不发生任何异常),都要执行的部分,;,6.2.1,异常处理的基本结构,说明:,(,1,),try,语句指明可能产生异常的代码段,;,(,2,),catch,语句在,try,语句之后,用于捕捉异常,一个,try,语句可以有多个,catch,语句与之匹配。当有多个,catch,语句时,系统依照先后顺序逐个检查。用,catch,语句捕捉异常时,若找不到相匹配的,catch,语句,将执行缺省的异常处理。,(,3,)将,catch,程序块的参数不能设置成多个,一个,catch,只有一个参数,.,6.2.1,异常处理的基本结构,说明:,(,4,)若两个,catch,程序块(均和某个,try,程序块有关)都用于捕捉同一类型异常,那么将产生语法错误。,(,5,)若某一类型异常,可能有几个异常处理程序与他相匹配,那么执行,first,相匹配的异常处理程序,(,6,),java,中可以使用嵌套的,try,catch,结构。在使用嵌套的,try,块时,将先执行内部,try,块,如果没有遇到匹配的,catch,块 则将检查外部,try,块的,catch,块。,6.2.1,异常处理的基本结构,throw,语句,用于指出当前现有异常,当程序执行到,throw,语句时,流程就转到相匹配的异常处理语句,所在的方法也不再返回值。,throw,语句可以将异常对象提交给调用者,以进行再次处理。,throws,语句,指明方法中可能要产生的异常类型,由调用者进行异常处理。,6.2.1,异常处理的基本结构,【,实例,6-1】,public class,DividerByZero,public static void,main(String,args,),double num=1;,try ,num=1/0;,catch(,ArithmeticException,e),System.out.print(An,arithmetic exception occurred!);,6.2.1,异常处理的基本结构,【,实例,6-1】,运行结果为:,An arithmetic exception occurred!,说明:,在本实例中,,try,语句块中语句,num=1/0,被执行时,由于被除数为,0,,因此产生,ArithmeticException,异常,,catch,语句捕获到这类异常后,输出“,An arithmetic exception occurred!”,。,6.2.2,多个,catch,块,单个try块能有许多catch块,当try块有可以引起不同类型异常的语句时,多个catch块是必须的。,【实例6-2】,public class TryCatch,public static void main(String args),int a=0,0;,int num=1,result=0;,try ,result=num/0;,System.out.println(num/a2);,catch(ArithmeticException e),System.out.println(Errore);,catch(ArrayIndexOutOfBoundsException e),System.out.println(Errore);,catch(Exception e),System.out.println(Some other error:);,【实例6-2】,运行结果:,Error=java.lang.ArithmeticException:/by zero,说明:在本实例中,,(1)执行语句result=num/0;出现被零除异常,此时执行catch(ArithmeticException e)块中的语句。此时语句System.out.println(num/a2);没有执行到。,(2)如果将result=num/0;注释掉,那么当执行语句“System.out.println(num/a2);”时会出现数组下标越界异常ArrayIndexOutOfBoundsException,因此此时运行结果为:,Error=java.lang.ArrayIndexOutOfBoundsException:2,(3)若出现其他Exception异常,则由catch(Exception e)捕获,显示Some other error:。,6.2.3 finally,语句,finally,语句可以和,try,语句一起使用,无论是否出现异常,,finally,语句指明的代码一定被执行。一个异常处理程序只有一个,finally,块,但并不强制必须要有,finally,块。,有时,必需处理某些语句(如文件关闭操作),不管异常是否发生,都必须执行。此时,虽然能够在,try,和,catch,块放置代码以结束文件,但是为了避免重写代码,可以把代码放在,finally,块。,有时候我们希望某些语句在发生异常时也能执行,以释放外部资源或者关闭一个文件,这时可以用,finally,语句来实现。,【实例6-3】,import.*;,import java.io.*;,class withoutFinallyExample,public void foo()throws IOException,/在空闲的端口上创建一个套接字,ServerSocket ss=new ServerSocket(0);,try,Socket socket=ss.accept();,/此处的其他代码.,catch(IOException e),ss.close();/label1,throw e;,/.,ss.close();/label2,【实例6-3】,问题,上述代码没有finally块,程序中创建了一个套接字,并调用 accept 方法。在退出该方法之前,必须关闭此套接字,以避免资源漏洞。为此,在/label2处调用 close来关闭此套接字,此语句为该方法的最后一条语句。正常情况下,/label2处的close会执行,但是,如果 try 块中发生一个异常会时,/label2处的close语句是不会执行的,即在这种情况下,套接字没有关闭,可能产生资源漏洞。因此,程序中必须捕获这个异常,并在重新发出这个异常之前在/label 1 处插入对 close 的另一个调用。这样就可以确保在退出该方法之前关闭套接字。,但上述编写代码方式既麻烦又易于出错,但在没有 finally 的情况下这是必不可少的。以下借助finally块来解决这个问题。,【实例6-4】,import.*;,import java.io.*;,class WithFinally,public void foo2()throws IOException,/在空闲的端口上创建一个套接字,ServerSocket ss=new ServerSocket(0);,try,Socket socket=ss.accept();,/此处的其他代码.,finally,ss.close();,6.3,两种抛出异常的方式,6.3.1 throw 直接抛出,6.3.2 throws间接抛出异常(声明异常),6.3.1 throw,直接抛出,直接抛出异常,是在方法中用关键字,throw,引发明确的异常。当,throw,被执行时,其后语句将不再被执行,执行流程将直接寻找,catch,语句并进行匹配,throw e,。显然,这种异常不是出错产生,而是人为地抛出。,throw,抛出异常的格式为:,throw ThrowableObject;,例如:,throw new ArithmeticException();,【实例6-5】,class JavaThrow 1,public static void main(String args),System.out.print(“Now”);,try,System.out.print(“is”);,throw new NullPointerException();/直接抛出一个异常;,/System.out.print(“This will not execute!”);/此句不被执行,catch(NullPointerException m),System.out.print(“the”);,System.out.print(“time.n”);,运行结果为:,Now is the time,.,说明:,在本实例中,“throw new NullPointerException();”用于人为抛出异常NullPointerException,catch(NullPointerException m)块对这类异常进行处理。,注意:,语句,System.out.print(“This will not execute!”);必须注释起来,,否则编译时会出现如下错误。,6.3.2 throws,间接抛出异常,说明:,如果一个方法可能导致一个异常但不处理它,此时要求在方法声明中包含,throws,子句通知潜在调用者,在发生异常时沿着调用层次向上传递,由调用它的方法来处理这些异常。这类异常成为声明异常。,基本格式为:,类型 方法名(参量表),throws,异常列表,代码,【实例6-10】,class ThrowsExceptionExample1,private static void p()throws ArithmeticException,/间接抛出异常,自己并未处理,让方法的直接调用者来处理,int i;,i=4/0;/此句可能引发异常,可是自己并未处理,public static void main(String args),try,p();/方法的直接调用者俘获处理异常,catch(ArithmeticException e),System.out.println(“Error:Divider is zero!n”);,【实例6-10】,运行结果为:,Error:Divider is zero!,说明:,在本实例中,语句i=4/0;将产生异常,产生异常后方法p()并不作处理,而是由调用p()的方法main做处理。,6.4,自定义异常,通过继承,Exception,类或它的子类,实现自定义异常类。,对于自定义异常,必须采用,throw,语句抛出异常,这种类型的异常不会自行产生。,可以通过扩展,Exception,类来创建异常类。,用户定义的异常同样要用,try,catch,捕获,但必须由用户抛出,throw new MyException,。,【实例6-11】,/myException.java,class myException extends Exception,class UserTrial,int num1,num2;,public UserTrial(int a,int b),num1=a;num2=b;,void show()throws myException,if(num10),throw new myException();,System.out.println(Value1=+num1);,System.out.println(Value2=+num2);,【实例6-11】,class myExceptionThrow,public static void main(String args),UserTrial trial=new UserTrial(-1,1);,try,trial.show();,catch(myException e),System.out.println(Illegal Values:Caught in main);,【实例6-11】,代码说明:,(1)在上述给出的代码里,称myException类从Exception类扩展而来。,(2)UserTrial类有一个能引发称为myException的自定义异常的方法。,(3)在 myExceptionThrow类里的 main()方法创建 UserTrial类的对象并传送错误值给构造方法。,(4)main()方法的 try块调用 show()方法。,(5)show()方法引发异常,由异常处理程序在main()方法里捕获。,(6)显示在catch 块里的消息,Illegal Values:Caught in main(非法的值:在main中俘获),被显示在屏幕上。,【实例6-11】,运行结果为:,Illegal Values:Caught in main,说明:,由于执行创建对象语句UserTrial trial=new UserTrial(-1,1);num1与num2的值满足异常触发条件。若将此创建对象语句变为创建UserTrial trial=new UserTrial(1,-1);此时num1与num2的值不满足异常触发条件,异常未触发,运行结果为:,Num1=1,Num2=-1,6.5,常见异常,RuntimeException,Java.lang,包中多数异常的基类,ArithmeticException,算术错误,如除以,0,IllegalArgumentException,方法收到非法参数,ArrayIndexOutOfBoundsException,数组下标出界,NullPointerException,试图访问,null,对象引用,SecurityException,试图违反安全性,ClassNotFoundException,不能加载请求的类,6.5,常见异常,NumberFormatException,从字符串到数字格式的非法转换,AWTException,AWT,中的异常,IOException,I/O,异常的根类,FileNotFoundException,不能找到文件,EOFException,文件结束,IllegalAccessException,对类的访问被拒绝,NoSuchMethodException,请求的方法不存在,InterruptedException,线程中断,NullPointerException,异常,
展开阅读全文