




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第八章
异常处理(Exception)8.1异常分类8.2引发异常8.3声明抛出异常8.4捕捉异常8.5定义自己的异常类型8.6构造方法与异常处理8.7小结1try-catch-finally语句,其语法格式:try{//可能发生异常的代码
}catch(异常类型1变量){//<异常类型1>异常的处理代码}catch(异常类型2变量){//<异常类型2>异常的处理代码}.....finally{//总是要执行的代码
}产生异常语句throw抛出异常异常类结构异常的方法finally机制2异常(例外)是方法代码运行时出现的非正常状态,这种非正常状态使程序无法或不能再正常地继续往下运行。常见的异常:数组下标越界除数为零内存溢出文件找不到等。3异常对象记录着这个异常的一些描述和状态信息。方法运行失败时,记录这个异常信息的异常对象将产生(或称为引发,抛出,throw),它有两种引发方式:1系统自动引发2在程序中由throw语句引发异常对象引发后,系统根据异常对象的类型,首先在当前方法寻找相应的异常处理代码,找到后就将控制流转入该异常处理代码并向其传递异常对象(称为捕获该异常,catch),异常处理代码可以根据接受到的异常对象进行相应的处理;5寻找相应的异常处理代码的过程:当前方法直接或间接调用者找到,传递异常对象并进行异常处理没有找到,调用默认的异常处理程序,中止当前线程
6举例(没有异常处理的情况)1)classExceptionDivideBy0{2)staticvoidmethod(){intx=0,z=10;
int
y=10/x;
System.out.println("z="+z);}publicstaticvoidmain(String[]args){method();
System.out.println("After
method.");}11)}7具有异常处理的情况classExceptionDivideBy0{staticvoidmethod(){intx=0,z=10;try{inty=10/x;
System.out.println("z="+z);}catch(ArithmeticExceptione){ System.out.println("ArithmeticException");}System.out.println("Aftertry/catchblocks.");}publicstaticvoidmain(String[]args){method();System.out.println("Aftermethod.");}}9ArithmeticExceptionAftertry/catchblocks.Aftermethod.10每个异常由类Throwable或者它的一个子类的实例表示,这样的对象可被抛出并能被传递给合适的异常处理代码处理。Throwable类及其子类统称为异常类,每个异常类表示一种异常类型。Throwable类是Object类的直接子类,其本身又有两个直接子类:Error与Exception类。RuntimeException类是Exception类的直接子类,如图8-1所示。这里,Error类、RuntimeException类和Exception类分别代表某一类异常类型:8.1异常分类11(1)Error类及其子类:表示灾难性的、普通程序很难恢复的异常,例如:●NoClassDefFoundError(类定义没找到异常):JVM无法找到相应的class文件。●OutOfMemoryError(内存越界异常):JVM没有足够的存储空间满足对象创建的要求。●NoSuchMethodError(调用不存在的方法异常):在改变某个方法的签名后,原先要调用该方法的应用程序,在运行时就会抛出该异常。一般情况下,程序员可不必理会这类异常,它们虽然很严重,但很少发生。13(2)RuntimeException类及其子类:表示设计或实现方面的问题,例如:●ArithmeticException(算术运算异常):算术运算时发生的异常情况,如整数相除,除数为零。●ClassCastException(强制类型转换异常):把一个对象引用转换成一个不合适的类型,如把一个对象引用转换成某个子类类型。●NullPointerException(空引用异常):需要对象引用时使用了一个null引用。●ArrayIndexOutOfBoundsException(数组下标越界异常):下标值超出了数组大小。●NumberFormatException(数字格式异常):试图将非数字格式字符串转换成数值。14(3)Exception类及其非RuntimeException子类:表示运行时因环境的影响而引发的异常,例如:●IOException(输入输出异常):在I/O操作失败或者被中断时引发。其子类包括:EOFException、、InterruptedIOException等。●InterruptedException(中断异常):当前等待或睡眠线程被其他线程中断时引发。这类异常并非因设计或实现引起,是无法避免的。但一般情况下,程序员应该提供相应的代码捕捉和处理。15受检查的异常和不受检查的异常:不受检查的异常:类Error和类RuntimeException及其子类属于不受检查的异常,如图8-1所示。不受检查的异常不受编译系统的检查。对这类异常,程序员可以捕捉或声明抛出,但通常可以不加理会。17异常类的方法和属性
(1)异常类的构造方法publicException()创建新异常。publicException(Stringmessage)用字符串参数message描述异常信息创建新异常。(2)异常类的方法publicStringtoString()返回描述当前异常对象信息的字符串。publicStringgetMessage()返回描述当前异常对象的详细信息。publicvoidprintStackTrace()在屏幕上输出当前异常对象使用堆栈的轨迹,即程序中先后调用了哪些方法,使得运行过程中产生了这个异常对象。18所谓异常的引发是指因程序运行出现异常情况而产生异常对象、进而转入异常处理过程的情形。Java运行系统在发现异常情况时会自动引发异常。自动引发异常如下例:8.2引发异常19throw引发异常异常既可以在发生异常情况时由运行系统引发,也可以在程序中用throw语句显式引发。格式如下:
thrownewArithmeticException();21【例8-2】下面程序在被减数a小于减数b时将引发ArithmeticException异常。1)classTest{2)staticintmethod(inta,intb){3)if(a<b)4)thrownewArithmeticException("a<b");//产生异常5)returna-b;6)}7)publicstaticvoidmain(String[]args){8)method(3,5);9)}10)}下面是该程序的输出结果:Exceptioninthread"main"java.lang.ArithmeticException:a<batTest.method(Test.java:4)atTest.main(Test.java:8)22如果一个方法引发的是受检查的异常且自己没有捕捉,那么它必须用throws子句声明抛出;该方法的调用者如果不对异常进行捕捉,那么也必须用throws子句声明抛出。下面是包含throws子句的方法定义的语法格式:
<返回类型><方法名>(<参数列表>)throws<异常类型列表>{...}8.3声明抛出异常23对不受检查的异常,同样可以声明抛出(或进行捕捉),这在语法上是允许的。无论是受检查的异常还是不受检查的异常,对不受检查的异常,不管是否声明了异常抛出,异常一旦引发,其处理过程是一致的,即:异常沿着方法调用的反方向传播,寻找并转入合适的异常处理代码执行。如果方法及其所有的调用者都没有提供合适的处理代码,那么异常将最终传播到运行系统,运行系统调用默认的异常处理代码后终止程序执行。图8-2说明了例8-2和例8-3中异常引发和传递的过程。25图8-2异常传播过程示意图26请问下面哪些BaseClass类的子类定义是合法的?A)classAextendsBaseClass{voidmethod()throwsIOException{}}B)classBextendsBaseClass{voidmethod()throwsException{}}C)classCextendsBaseClass{
voidmethod()throwsEOFException,{}}29D)classDextendsBaseClass{voidmethod()throwsIOException,InterruptedException{}}E)classEextendsBaseClass{voidmethod(){}}F)classFextendsBaseClass{voidmethod()throwsIOException,NullPointerException{}}30【例2.10】从键盘输入一个整数和实数,并输出它们的和
importjava.io.*;//引入java.io包classInputDemo{publicstaticvoidmain(Stringargs[])throwsIOException{//用标准输入System.in创建一个BufferedReaderBufferedReaderbr=newBufferedReader(newInputStreamReader(System.in));
System.out.print("请输入一个整数:");Stringstr=br.readLine();//输入字符行存入字符串inti=Integer.parseInt(str);//转换字符串为整型数据31System.out.print("请输入一个实数:");str=br.readLine();floatf=Float.parseFloat(str);System.out.print("它们的和是:"+(i+f));}}32如果不加以捕捉,引发的异常将沿着方法调用的反方向往外抛出和传播,直至Java运行系统。通常,这并不是所希望的结果。一般来说,引发异常的方法的调用者应该捕捉,并根据具体情况处理异常,从而阻止异常继续往外传播。Java使用try-catch-finally语句来捕捉和处理可能发生的异常,该语句的语法格式如下:8.4捕捉异常33try{//此处是可能发生异常的代码}catch(<异常类型1><异常引用变量>){//<异常类型1>异常的处理代码}catch(<异常类型2><异常引用变量>){//<异常类型2>异常的处理代码}…finally{//总是要执行的代码}该语句包含try、catch和finally三个子句。其中,catch子句可以有多个,而且至少有一个catch子句或finally子句。34try子句包含一段可能要发生异常的代码。一旦发生异常,将由后面的catch子句捕捉处理。每个catch子句有一个参数,参数类型指明该子句能够捕捉的异常类型。如果子句指定的参数类型是所发生的异常的类或者是其超类,则说明catch子句能够捕捉该异常。此时,运行系统将把异常对象的引用值传递给catch子句的参数变量,并将控制流转移到该catch子句,执行子句内的异常处理代码。之后,接着执行try语句后面的代码。如果try子句内的代码没有发生任何异常,那么跳过catch子句,直接执行try语句后面的代码。8.4.1try和catch子句35classDemo{publicstaticvoidmain(String[]args){try{inta=args.length;System.out.println("a="+a);intb=42/a;int[]c={1};c[4]=99;}catch(ArithmeticExceptione)//捕获算术运算异常{System.out.println("Divideby0:"+e);}
catch(ArrayIndexOutOfBoundsExceptione){System.out.println("Arrayindexoob:"+e);}System.out.println("Aftertry/catchblocks.");}}【例8-5】try和catch子句举例36a=0Divideby0:java.lang.ArithmeticException:/byzeroAftertry/catchblocks.37最后说明两点:(1)当发生异常时,如果有catch捕捉到了异常,那么不管具体的异常处理代码如何(甚至不含任何语句),Java运行系统都认为该异常已被消除;(2)当执行完异常处理代码后,控制流并不会回到异常发生处,而是执行try语句后面的代码(如果没有finally子句)。38try子句内的代码可能会发生多种类型的异常,而try语句也允许有多个catch子句,每个catch子句可以捕捉一种类型(包括子类型)的异常。当然,每次执行try语句时,至多只能抛出一个异常,相应地,至多只能有一个异常处理代码被执行。
8.4.2多个catch子句39当异常发生时,运行系统将按先后次序依次判断各catch子句,如果发现某个catch子句能够捕捉该异常,就执行其中的处理代码,而其后面的catch子句将被忽略。注意:处理子类型异常的catch子句一定要放在处理超类型异常的catch子句之前。如果将一个处理超类型异常的catch子句放在处理子类型异常的catch子句之前,或者两个catch子句捕捉同一类型的异常,编译系统都将给出错误信息。40publicclassTest2{publicstaticvoidmain(String[]args){intx=0;inty;try{y=100/x;}catch(Exceptionex){ex.printStackTrace();}catch(ArithmeticExceptionex){ex.printStackTrace();}}}(ArithmeticExceptionex)(Exceptionex)Test2.java:9:已捕捉到异常java.lang.ArithmeticExceptioncatch(ArithmeticExceptionex)^1错误编译不通过:41使用finally子句的好处是:控制流不管以何种原因离开try语句,都要先执行finally子句。所以,可以将那些无论是否发生异常、异常无论是否被捕捉都需要执行的代码放置在finally子句内。8.4.3finally子句42控制流离开try语句的情况可分为以下几种:●try子句代码正常执行,没有引发异常;●try子句代码执行时引发异常,但被catch子句捕捉处理;●try子句代码执行时引发异常,但没有catch子句能捕捉处理;●try子句代码执行时引发异常,且被catch子句捕捉,但在执行异常处理代码时发生新的异常。注意:因return、break或continue等跳转语句(不管是出现在try子句中,还是出现在catch子句中)要离开try语句时,同样需要先执行finally子句。431)classFinallyDemo{2)staticvoidm1(inti){3)try{4)if(i==2){5)System.out.println("第2种情况:发生算术运算异常");6)thrownewArithmeticException();7)}if(i==3){8)System.out.println("第3种情况:发生数字格式异常");9)thrownewNumberFormatException();10)}if(i==4){11)System.out.println("第4种情况:发生数组下标越界异常");12)thrownewArrayIndexOutOfBoundsException();13)}14)System.out.println("第1种情况:没有发生异常");15)}【例8-9】finally子句举例4415)catch(ArithmeticExceptione)16){System.out.println("异常被捕捉处理");}17)catch(ArrayIndexOutOfBoundsExceptione)18){System.out.println("异常被捕捉,但又被重新引发");19)throwe;}20)finally21){
System.out.println("这是finally子句");
}23)System.out.println("这是try语句后的代码");24)}25)publicstaticvoidmain(Stringargs[])26){for(inti=1;i<5;i++)27){try28){m1(i);}29)catch(RuntimeExceptione)30){System.out.println("由main方法捕捉到异常");}
}
}}45下面是程序的输出结果:第1种情况:没有发生异常这是finally子句这是try语句后的代码第2种情况:发生算术运算异常异常被捕捉处理这是finally子句这是try语句后的代码46下面是程序的输出结果(续):第3种情况:发生数字格式异常这是finally子句由main方法捕捉到异常第4种情况:发生数组下标越界异常异常被捕捉,但又被重新引发这是finally子句由main方法捕捉到异常47当try子句发生异常时,如果没有一个catch子句能够捕捉到,则异常从该try语句抛出并向外传播。如果try语句本身是另外一个try语句的try子句的一部分,那么异常就由该外层try语句的catch子句捕捉处理。如果没有外层的try语句,或者外层try语句也没有catch子句能够捕捉该异常,则异常被传播到方法的调用者那里,由调用方法处理。8.4.4未捕捉到的异常481)classTest{//例8-7未捕捉到的异常被传播并由调用方法捕捉。2)staticvoidm1(Strings){3)try4){intx=Integer.parseInt(s);5)inty=10/x;}6)catch(NumberFormatExceptione)7){System.out.println("caught"+e+"inm1");}8)System.out.println("exitingfromm1");9)}10)publicstaticvoidmain(Stringargs[]){11)try12){m1(args[0]);}13)catch(ArrayIndexOutOfBoundsExceptione)14){System.out.println("caught"+e+"inmain");}15)catch(ArithmeticExceptione)16){System.out.println("caught"+e+"inmain");}17)System.out.println("exitingfrommain");18)}}49该程序可以在不同情况下发生3种不同类型的异常。如果命令行不提供参数,下面是程序的输出结果:C:\\>javaTestcaughtjava.lang.ArrayIndexOutOfBoundsException:0inmainexitingfrommain如果命令行的第1个参数为非数字格式字符串,下面是程序的输出结果:C:\\>javaTestaaacaughtjava.lang.NumberFormatException:aaainm1exitingfromm1exitingfrommain如果命令行的第一个参数为数字0,下面是程序的输出结果:C:\\>javaTest0caughtjava.lang.ArithmeticException:/byzeroinmainexitingfrommain50try子句发生的异常可以由语句中的某个catch子句捕捉处理,但在执行catch子句内的异常处理代码时也可能再引发新的异常。此时,原先的异常被遗弃,新的异常从try语句抛出并向外传播。与"未捕捉到的异常"类似,该新异常或者由外层try语句的catch子句捕捉,或者由方法的调用者处理。8.4.5再引发异常511)importjava.io.IOException;//【例8-8】再引发异常举例2)classTest{3)staticvoidm1()throwsIOException{4)try5){thrownewRuntimeException("demo_1");}6)catch(RuntimeExceptione)7){System.out.println("caught"+e+"inm1");8)thrownewIOException("demo_2");}9)}10)publicstaticvoidmain(Stringargs[]){11)try12){m1();}13)catch(IOExceptione)14){System.out.println("caught"+e+"inmain");}15)System.out.println("exitingfrommain");16)}17)}52下面是程序的输出结果:caughtjava.lang.RuntimeException:demo_1inm1caughtjava.io.IOException:demo_2inmainexitingfrommain53
8.5定义自己的异常类型
自定义的异常类型必须是Throwable类的子类。只有Throwable类及其子类的实例才能够被引发和捕捉。
通常将自定义异常类型定义成Exception的子类,以产生受检查的异常。
Java异常处理机制的特点是方法的调用者必须认识和处理方法可能会抛出的受检查异常,而对不受检查的异常,调用者则可以不加理会。54例:在定义银行类时,若取钱数大于余额则作为异常处理(InsufficientFundsException)。思路:
产生异常的条件是余额少于取额,因此是否抛出异常要先判断该条件。确定产生异常的方法,应该在取钱方法withdrawal中产生异常InsufficientFundsException
。
处理异常安排在调用withdrawal的时候,因此withdrawal方法要声明异常,由上级方法捕获并处理。要定义好自己的异异常。55publicclassInsufficientFundsExceptionextendsException{privateBankexcepbank;privatedoubleexcepAmount;
InsufficientFundsException(Bankba,doubledAmount){excepbank=ba;excepAmount=dAmount;}publicStringtoString(){Stringstr="Thebalance"+excepbank.getbalance()+"Thewithdrawalwas"+excepAmount;returnstr;}}56classBank{doublebalance;//余额
publicvoiddeposite(doubledAmount)//存钱
{if(dAmount>0.0)balance=balance+dAmount;}publicvoidwithdrawal(doubledAmount)throwsInsufficientFundsException{//取钱if(balance<dAmout){
thrownewInsufficientFundsException(this,dAmount);}balance=balance-dAmount;}publicdoublegetbalance()//获取余额
{returnbalance;}}57publicclassExceptionDemo{publicstaticvoidmain(Stringargs[]){try{Bankba=newBank();ba.deposite(50);
ba.withdrawal(100);System.out.println("Withdrawalsuccessful!");}catch(Exceptione){System.out.println(e.toString());}}}58【例】设计自己的异常。从键盘输入一个double类型的数,若不小于0.0,则输出它的平方根,若小于0.0,则输出提示信息"输入错误!"。
importjava.io.*;classMyExceptionextendsException{ doublex; MyException(doublex) {this.x=x;}publicStringtoString(){return"输入错误:x<0.0"+"x="+x;}}59publicclassMySqrt{staticvoidtest(doublex)throwsMyException{if(x<0.0)thrownewMyException(x);elseSystem.out.println(Math.sqrt(x));}publicstaticvoidmain(Stringargs[])throwsIOException{try
{System.out.print("求输入实数的平方根,请输入一个实数:");BufferedReaderbr=newBufferedReader(newInputStreamReader(System.in));Strings=br.readLine();
test(Double.parseDouble(s));
}catch(MyExceptionClasse){System.out.println(e.toString());}
}}60与普通方法一样,构造方法也可以引发异常、捕捉异常或者声明抛出异常。实际上,构造方法有时比普通方法更需要使用异常处理机制。对于普通方法,有时可以通过返回一个特殊值来表示其执行出现了异常。例如,一个方法的返回类型是一种引用类型,且在正常情况下它总是能返回一个对象的引用,那么就可以返回一个null值表示非正常情况,而不是抛出异常。这种处理方式不适用于构造方法。构造方法没有返回类型,构造方法体不能使用带表达式的return语句。下面是构造方法
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 单位网球协会管理制度
- 医院住院欠费管理制度
- 厦门实名考勤管理制度
- 医疗器械入库管理制度
- 医院儿科感染管理制度
- 库存地板仓库管理制度
- 健身会所保洁管理制度
- 培训机构消毒管理制度
- 医院核心人才管理制度
- 办公住宿接待管理制度
- 2024年湖北省中考地理生物试卷(含答案)
- 床上用品、服装产品供货及售后服务方案
- 绿色施工管理体系及管理制度汇编
- DB33∕T 2357-2021 未来社区商业建设及运营规范
- 工学结合一体化课程教学设计的编写(课堂PPT)
- 公路运营之隧道知识培训
- 四大管道标准学习20130814-沧州
- 施耐德公司品牌战略
- 论文新建成品油库设计
- 第五章 包壳材料
- 银行股份有限公司个人存款挂失业务管理办法
评论
0/150
提交评论