版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第6章异常处理6.1程序错误与处理6.2Java的异常处理6.3自定义异常类6.4编程实例 6.1程序错误与处理程序中的错误有不同的性质,不同的错误需要采用不同的处理方式。按照错误的性质可将程序错误分成3类:语法错、语义错、逻辑错。6.1.1程序错误、发现时刻及错误处理原则1.语法错违反语法规范的错误称为语法错,这类错误通常在编译时发现,又称为编译错。Java编译器能够发现所有语法错,给出错误的位置和性质。程序员必须及时改正语法错,再重新编译程序。2.语义错如果程序在语法上正确,但在语义上存在错误,则称为语义错,如除数为0错、给变量赋予超出其范围的值、待打开的文件不存在等。语义错不能被编译系统发现,只能到程序运行时才能被系统发现,因而又称为运行错。在运行时,一旦发现了语义错,Java将停止程序运行,并给出错误的位置和性质。有些语义能够被程序事先处理,程序中应该设法避免产生这些错误;还有一些语义错不能被程序事先处理,这些错误的发生不由程序本身所控制,因此必须进行异常处理。3.逻辑错如果程序通过编译,可运行,但运行结果与期望值不符,则这类错误称为逻辑错。由于系统无法找到逻辑错,所以逻辑错最难确定和排除。此时,程序员必须凭借自身的程序设计经验,找到错误原因及出错位置,从而改正错误。6.1.2面向过程语言与面向对象语言的错误处理方式比较
面向过程语言——程序运行效率更重要语言本身防范错误的责任推给了程序员,使程序质量完全依赖于程序员。程序员必须考虑并防范所有错误,为每一个应用程序设置语言一级的错误处理机制,这对程序员的要求太高。再者,含有错误处理的程序代码臃肿,逻辑复杂,可读性差,软件无法维护和升级。在程序开发过程中,程序员能够发现并改正语法错和逻辑错,但无法防范所有运行时错误,这些错误的出现不是由程序控制的,面向过程语言没有提供对这些错误的防范和处理机制,只能任凭错误的产生而导致程序运行中断。
6.1.2面向过程语言与面向对象语言的错误处理方式比较面向对象语言——程序的正确性、可靠性和稳定性更重要提供语言级的错误防范和处理机制,即异常处理机制。异常处理是捕获和处理运行时错误的一种机制。异常处理机制使程序具有处理错误的能力,即使发生了运行时错误,应用程序能够捕获异常并及时处理异常,使程序从运行时错误中很好地恢复并继续运行,而不会导致程序运行非正常终止。异常处理是一种对异常进行事后处理的机制。异常处理机制将运行时错误封装成若干错误类和异常类,并提供异常处理语句用于在程序中实现对运行时错误的发现和及时处理。6.1.3Java的错误和异常一、错误与异常根据错误的性质,Java将运行时错误分为两类:错误和异常。(1)错误(error)错误指程序运行时遇到的硬件或操作系统的错误,如内存溢出、虚拟机错误等。错误对于程序而言是致命的,错误将导致程序无法运行,而且程序本身不能处理错误,只能依靠外界干预,否则会一直处于非正常状态。(2)异常(exception)异常指在硬件和操作系统正常时,程序遇到的运行错,如操作数超出数据范围,文件不存在等。异常对于程序而言是非致命性的,虽然异常会导致程序非正常终止,但Java的异常处理机制使程序自身能够捕获和处理异常,由异常代码调整程序运行方向,但程序仍可继续运行。图6.1Java程序发现错误和异常二、错误类和异常类Java中的所有的错误类和异常类都是从Throwable类派生出来的。Throwable是异常类的根节点,定义在java.lang包,它的子类也定义在该包中。Throwable类有两个直接子类:java.lang.Error和java.lang.Exception。Error代表系统错误类,由系统直接处理;Exception类及其子类是在程序中可捕捉到的异常。图6.2错误类和异常类的层次结构(1)Error类Error类是错误类,Error类对象由Java虚拟机生成并抛出给系统,有内存溢出错误、栈溢出错误、动态链接错误等。例如,当运行没有main()方法的类时,则产生类定义未找到错误(NoClassDefFoundError)。(2)Exception类Exception类是异常类,Exception类对象是Java程序捕获和处理的对象。每一种异常对应Exception类的一个子类,异常对象中包含错误的位置和特征信息。每个异常类反映一类运行时错误,类定义包含了该类异常的信息和对异常进行处理的方法。Java预定了多种通用的异常类,如除数为0的算术异常、数组下标越界异常、空指针异常等,程序中也可以自定义异常类。每当程序运行过程中发生了某个异常现象,系统将产生一个相应的异常类对象,并交由系统中的相应机制进行处理,以避免死机、死循环或其他对系统不利的结果发生,保证了程序运行的安全性。三、Error错误类的子类
Error类及其子类主要用来描述一些Java运行时的系统内部错误或资源枯竭导致的错误。普通的程序不能从这类错误中恢复,也无法抛出这种类型的错误,这类错误出现的几率是很小的。
(1)VirtualMachineError虚拟机错误OutOfMemoryError内存溢出错误StackOverflowError栈溢出错误(2)LinkageError链接错误(3)java.awt.AWTError图形界面错误
Throwable类的一个异常类分支是Exception类和它的子类。在编程中,对异常的处理主要是对这类异常的处理。类Exception是普通程序可以从中恢复的所有标准异常的超类。
Exception类又有两个分支:从RuntimeException中派生出来的类和从Non-RuntimeException类中派生的类,这样分类的根据是错误发生的原因。
四、Exception异常类的子类(1)RuntimeException运行时异常类,是程序员编写程序不正确所导致的异常,理论上,程序员经过检查和测试可以查出这类错误。该异常可能出现在程序的任何地方,而且出现的可能性非常大,如果由程序本身去检测运行异常出现与否,将会使程序的负荷过大,因而编译器并不要求程序去说明或捕获运行时异常。(2)Non-RuntimeException非运行时异常类,是由于一些异常的情况造成的,不是程序本身的错误,可以由编译器在编译时检测到的、可能会发生在方法执行过程中的异常。比如:输入/输出错误(IOException)、试图为一个不存在的类找到一个代表它的class类的对象(ClassNotFoundException)等。这不是程序本身的错误,如果这些异常情况没有发生,程序本身仍然是完好的。如果程序没有适当地处理可能会引发运行异常的语句,则程序将不能通过编译器的编译。(一)RuntimeException类主要包括以下异常子类:·ArithmeticException算术异常类:表示遇到了异常的算术问题,例如被0整除。·ArrayStoreException数组内容异常类:试图把与数组类型不相符的值存入数组。·ClassCastException类型强制转换异常类:试图把一个对象的引用强制转换为不合适的类型。·IndexOutOfBoundsException下标越界异常类:下标越界。·NullPointerException空指针异常类:试图使用一个空的对象引用。·SecurityException违背安全原则异常类:检测到了违反安全的行为。
1.java.lang.ArithmeticException0作除数(包括模),将产生这类异常。例如:intx=0,y;y=100/x;
2.java.lang.ArrayIndexOutOfBoundsException
例如:inta[]=newint[10];a[10]=0;
产生运行时异常类对象举例
3.
java.lang.ArrayStoreException例如:inta[]=newint[10];
booleanb[]=newboolean[10]; System.arraycopy(a,0,b,3,6);//有异常
4.java.lang.ClassCastException
例如:Objectobj=newObject();
inta[]=(int[])(obj);5.java.lang.NumerFormatException
例如:intj=Integer.parseInt(“abc”);
6.
java.lang.IndexOutOfBoundsException
例如:charch="ABC".charAt(99);
注意:2是6的子类。
7.java.lang.NegativeArraySizeException
例如:inta[]=newint[-10];
8.
java.lang.NullPointerException
例如:inta[]=null; System.out.print(a.length);
再如:inta[]=null;a[0]=1;1.IOException异常类IOException输入输出异常类,指示出现了某种I/O错误。这个类是由失败的或中断的I/O操作所产生的异常的总体类。IOException:申请I/O操作没有正常完成。EOFException:在输入操作正常结束前遇到了文件结束符。FileNotFoundException:在文件系统中,没有找到由文件名字符串指定的文件。(二)Non-RuntimeException类主要包括以下异常子类:2.EmptyStackException:试图访问一个空堆栈中的元素。3.NoSuchFieldException:试图访问一个不存在的域。4.NoSuchMethodException:试图访问不存在的方法。5.ClassNotFoundException:具有指定名字的类或接口没有被发现。6.CloneNotSupportedException:克隆一个没有实现Cloneable接口的类。7.IllegalAccessException:试图用给出了完整的路径信息的字符串加载一个类。8.InstantiationException:试图使用Class的newInstance方法创建一个对象实例。9.InterruptedException:当前的线程正在等待,而另一个线程使用了Thread的interrupt方法中断了当前线程。(二)Non-RuntimeException类主要包括以下异常子类:五、程序对错误与异常的三种处理方式(1)程序不能处理错误(2)运行时异常——程序应避免而不捕获异常(3)非运行时异常——必须捕获异常对于程序无法预见的、由特殊环境错误造成的异常,如文件没找到、网络通信失败等,必须进行捕获和处理,从而保证程序正常运行,保证程序的可靠性和安全性。6.2Java的异常处理6.2.1异常处理机制的优点例6.1异常处理方法演示。publicclassExceptionDemo{ staticint[]IntArrayAdd(int[]a,int[]b) {
int[]c=newint[a.length];
for(inti=0;i<c.length;i++) c[i]=a[i]+b[i]; returnc;}
publicstaticvoidmain(String[]args) {
int[]a=newint[20];
int[]b=newint[10];
for(inti=0;i<20;i++) a[i]=i;
for(inti=0;i<10;i++) b[i]=i;
try{
int[]c=IntArrayAdd(a,b);
for(inti=0;i<c.length;i++) System.out.print(""+c[i]); }catch(Exceptione){
System.out.println("Thereisanerror!"); } }}程序运行结果为:
Thereisanerror!
从第2章有关数组的知识可以知道,程序6.1的main方法在调用方法IntArrayAdd对数组b访问时下标超界,产生一个异常。由于程序6.1采用了Java语言中的异常处理方法,程序执行流程发生变化,转到语句System.out.println(“Thereisanerror!”)执行。观察一下程序6.1可以发现,程序中的错误在IntArrayAdd方法中发生,但是该方法中并没有错误处理语句,既没有用返回值标志错误发生,也没有设置一个main方法和IntArrayAdd方法可以共同访问的变量用于传递错误信息。那么,错误信息是怎样从IntArrayAdd方法传递到main方法的呢?实际上IntArrayAdd方法在超界访问数组元素时抛掷了一个异常,创建了一个异常对象用于存储错误信息,由于IntArrayAdd方法没有处理该异常,Java虚拟机终止IntArrayAdd方法的执行,然后自动返回到main方法,将流程转入异常处理部分。Java语言的异常处理机制的优点(1)从语法上看,异常处理语句将程序正常代码与错误代码分开,使程序的结构清晰,算法重点突出,可读性强。例如程序6.1的main方法中先调用IntArrayAdd方法然后输出结果,中间并没有插入错误处理的代码,而按照传统的方法,程序的结构应该是这样的:调用IntArrayAdd方法:
if(发生错误)
输出错误信息
else
输出结果当错误类型较多,需要分别处理时,采用这种方法很显然会使程序流程变得十分复杂。Java语言的异常处理机制的优点(2)异常处理机制带来的另一个好处是错误的传播。
Java异常会自动在方法调用堆栈中传播,例如程序6.1异常从IntArrayAdd方法自动传递到main方法。(3)Java异常处理机制克服了传统方法的错误信息有限的问题,可以针对不同的错误类型定义不同的异常类。
异常处理机制会根据异常对象的类型寻找匹配的错误处理代码。(4)从运行效果看,异常处理语句使程序具有处理错误的能力。即使发生了运行错,应用程序能够捕获异常并及时处理异常,使程序从运行错误中很好地恢复并继续运行,而不会导致程序运行非正常终止。而且,如果当前方法没有能力处理异常,还可以将异常转交给调用者处理。6.2.2异常处理机制
Java提供了异常处理机制来处理异常。分为三个步骤:
1.抛出异常
Java是这样规定的:当语义限制被违反时,将会抛出(throw)异常,即产生一个异常事件,生成一个异常对象,并把它提交给运行系统,再由运行系统寻找相应的代码来处理异常。一个异常对象可以由Java虚拟机来产生,也可以由运行的方法生成。异常对象中包含了异常事件类型、程序运行状态等必要信息。
2.捕获异常异常抛出后,运行时系统从生成异常对象的代码开始,沿方法的调用栈进行查找,直到找到包含相应处理的方法代码,并把异常对象交给该方法为止,这个过程称为捕获(catch)异常。
3.处理异常对异常对象执行相应操作,异常对象由捕获它的语句进行处理。
6.2.3异常的捕获除了继承自Error或RuntimeException的异常不需要处理之外,其他的异常都要进行处理,如例6.2。在程序中经常要做的一件事就是捕获、处理异常。异常处理代码块(catch{})中可以写上任何代码,事实上只要对该捕获的异常进行“catch”就可以,不作任何实质处理也可以通过编译。例6.2缺省的异常处理的情况。
publicclassDefaultException{publicstaticvoidmain(Stringargs[]){
inta,b=0;
a=2/b;//此处有异常
System.out.println(“a=”+a);//不运行此行
}}异常处理的格式:try{//接受监视的程序块,在此区域内发生的异常,由catch中指定的程序处理}//trycatch(异常类名1异常对象名1){//处理异常;}//catchcatch(异常类名2异常对象名2){//处理异常;}//catch……finally{//不论发生什么异常(或者不发生任何异常),都要执行的部分}//finally图6.3异常处理语句的执行流程将可能发生异常的程序代码放置在try程序块中。程序运行过程中,如果该块内的代码没有出现任何异常,则正常执行,后面的各catch块不起任何作用。但如果该块内的代码出现了异常,系统将终止try块的执行,自动跳转到所发生的异常类对应的catch块,执行该块中的代码。无论有没有异常,finally语句都会被执行。如例6.3。catch子句捕获异常的匹配规则如下:抛出异常对象与catch子句参数类型相同抛出异常对象为catch子句参数类的子类按照先后顺序捕获抛出异常对象,只捕获一次若找不到相匹配的catch语句,将执行缺省的异常处理,如例6.4。因此,通常最后一个catch子句的异常类参数声明为Exception,这样能够保证捕获和处理所有异常对象。异常处理的格式说明:例6.3如果try块内的代码出现了异常,系统将终止try块的执行,自动跳转到所发生的异常类对应的catch块。publicclassTryCatchTest{publicstaticvoidmain(Stringargs[]){
inta=99,b=0,c;
try{
System.out.println("产生异常之前"); c=a/b;//该行有异常
System.out.println("产生异常之后"); }catch(ArrayIndexOutOfBoundsExceptione){
System.out.println("处理下标越界异常"); }catch(ArithmeticExceptione){
System.out.println("处理算术异常"); }
System.out.println("异常处理结束");}}程序运行的结果:产生异常之前处理算术异常异常处理结束例6.4用catch语句捕捉异常时,若找不到相匹配的catch语句,将执行缺省的异常处理。publicclassTC2{publicstaticvoidmain(String[]args){
System.out.println(“这是一个异常处理的例子\n”);try{
inti=10;i/=0;}catch(IndexOutOfBoundsExceptione){
System.out.println("异常是:"+e.getMessage());}finally{
System.out.println("finally
语句被执行");}}}程序运行的结果:这是一个异常处理的例子对于一个try块,可以对应多个catch块,用于对多个异常类进行捕获。每个catch后的异常类名应不同,Java语言根据异常对象的类型从上向下匹配,执行第一个与之匹配的catch块。如果要捕获的诸类之间没有继承关系,各类的catch块的顺序就无关紧要,但如果它们之间有继承关系,那么应该将子类的catch块放置在父类的catch块之前。例如,当程序中数组下标超界时,Java抛掷出ArrayIndexOutOfBoundsExeption类的异常对象,该异常类是Exception的派生类,因此应将ArrayIndexOutOfBoundsExeption异常类的catch块放在Exception的前面。异常处理的格式说明:inta[]=newint[10];try{
for(inti=0;i<=10;i++) a[i]=i;}catch(ArrayIndexOutOfBoundsExeptione){
System.out.println("ArrayIndexoutofBounds");}catch(Exceptione){
System.out.println("Thereisanexception");}该程序段将输出:ArrayIndexoutofBounds而如果将两个catch块的顺序对调,则变成下面的形式:inta[]=newint[10];try{for(inti=0;i<=10;i++) a[i]=i;}catch(Exceptione){
System.out.println("Thereisanexception");}
catch(ArrayIndexOutOfBoundsExeptione){
System.out.println("ArrayIndexoutofBounds");}将执行第一个catch块,输出:
Thereisanexception其中finally块是个可选项,finally是异常处理的统一出口,如果有finally代码块,则不论怎样都会执行finally代码块中的内容。因此,finally代码块中常常放一些清理现场的代码,它可以保证不论出现什么异常都不致于造成严重后果。不过,finally代码块不是必须的,有些情况下并不必写finally代码块。finally语句不被执行的唯一情况是在try块内执行终止程序的System.exit()方法。注意:如果在调用能够产生异常的方法时没有进行捕获和处理,将不能通过编译。异常处理的格式说明:例6.5异常处理的执行顺序。publicclassFinallyBlock{ publicstaticvoidmain(String[]args) {
inti=0; Stringgreetings[]={ "Helloworld!", "No,Imeanit!", "HELLOWORLD!!“};
while(i<4){ try{System.out.println(greetings[i]); }catch(ArrayIndexOutOfBoundsExceptione){
System.out.println("Re-settingIndexValue"); i=-1; }finally{
System.out.println("Thisisalwaysprinted"); } i++; } }}程序运行时重复输出下面的内容,可按Ctrl+C终止:Helloworld!ThisisalwaysprintedNo,Imeanit!ThisisalwaysprintedHELLOWORLD!!ThisisalwaysprintedRe-settingIndexValueThisisalwaysprinted练习1:编写程序。程序运行结果如下:捕获算术异常!i=0a[1]/1=6i=1a[2]/2=3i=2a[3]/3=2i=3捕获数组下标越界异常!i=4继续!publicclassTry2{publicstaticvoidmain(Stringargs[]){
inti=0;
inta[]={5,6,7,8};
for(i=0;i<5;i++){try{
System.out.print("a["+i+"]/"+i+"="+(a[i]/i));}
catch(ArrayIndexOutOfBoundsExceptione){
System.out.print("捕获数组下标越界异常!");}
catch(ArithmeticExceptione){
System.out.print("捕获算术异常!");}
catch(Exceptione){
System.out.print("捕获"+e.getMessage()+"异常!");//显示异常信息}finally{
System.out.println("i="+i);}}
System.out.println("继续!");}}TestNo:1
零作除数!在finally块中!TestNo:2
数组下标越界!在finally块中!TestNo:3
下标越界!在finally块中!TestNo:4
在finally块中!练习2:用for和switch编写程序,程序运行结果如下:publicclasstestFinally{publicstaticvoidmain(Stringargs[]){
inta,b=0;
for(inti=0;i<=3;i++){
System.out.println("TestNo:"+(i+1));
try{ switch(i){ case0:a=3/b; break; case1:intc[]=newint[10]; c[10]=0; break; case2:charch="ABC".charAt(99); break; case3:return; } }catch(ArithmeticExceptione){
System.out.println(“零作除数!”); }catch(ArrayIndexOutOfBoundsExceptione){
System.out.println("数组下标越界!");}catch(IndexOutOfBoundsExceptione){
System.out.println("下标越界!");}finally{
System.out.println("在finally块中!"); }}}}
6.2.4异常的抛掷上面讲述的捕获异常是针对程序在运行过程中产生的可以预知、必须及时处理而且有明确的处理对策的异常,其结果可以给用户提供更多的、更友好的错误信息。但是有时也会碰到错误形式不确定的情况,随之而来的是不能或很难完整描述具体处理的方法。对于这种在程序中不能匹配捕获的异常,Java是不允许置之不理的,于是可以采取向外抛出的办法。
1.throw语句
throw语句格式:
<throw><new><异常类名()>;
例如:
thrownewException();
该语句直接调用Exception类的构造方法创建一个Exception类的对象并抛掷该对象。
Exception类从Throwable类派生而来,含有两个构造方法:
●publicException();●publicException(Stringmsg)。
根据错误类型的不同,创建的异常对象的类型也不相同。
throw语句的说明:
Throw语句是主动产生一个异常而非动态抛出。当程序执行到throw语句处,就立即人为地抛出一个异常,然后把控制转移到一个相应的catch块,不再执行throw后面的语句。在程序中使用throw语句来抛出异常,该异常可以在该程序中进行捕获、处理;也可以在调用它的程序中被处理。例6.6throw语句的使用,运行结果如图所示。publicclassTC5{staticvoidthrowProcess(){try{
thrownewNullPointerException("空指针异常");}
catch(NullPointerExceptione){
System.out.println("\n在throwProcess
方法中捕获一个"+e.getMessage());
throwe;}}
publicstaticvoidmain(Stringargs[]){try{
throwProcess();}catch(NullPointerExceptione){
System.out.println("再次捕获:"+e);}}}练习3:产生一个数组越界的异常,既在本方法体中处理,又通过throw语句将异常对象提交给调用者,以进行再次处理。程序运行结果如下:数组下标越界!下标越界!在finally块中!
publicclassThrowException{publicstaticvoidTest(){ try{
intc[]=newint[10]; c[10]=0; }catch(ArrayIndexOutOfBoundsExceptione){
System.out.println("\t
数组下标越界!"); throwe;//抛出点
//System.out.println("\t产生异常后!"); } }publicstaticvoidmain(Stringargs[]){ try{
Test(); }catch(IndexOutOfBoundsExceptione){
System.out.println("\t
下标越界!"); }finally{
System.out.println("\t
在finally块中!"); }}}
2.throws子句
Throws子句总是和方法说明出现在一起。方法说明告诉编译器该方法可能会产生哪些异常,从而要求它的调用者必须考虑处理这些异常。一个方法不处理它产生的异常,而是沿着调用层次向上传播,由调用它的方法来处理这些异常。建议:在多人合作写程序时,一个方法中产生的异常,最好在该方法中进行处理,不要将异常传播给其他人处理。图7.2throws异常的抛出及处理方法一方法二异常调用抛出处理Throws子句格式:在方法定义的头部加上:throws异常类名列表
<返回值类型><方法名><([参数])><throws><异常类名列表>{}例如:Thread类的方法sleep的定义为
publicstaticnativevoidsleep(longmills)throwsInterruptedException例6.7由调用者进行throws子句中的异常处理。importjava.io.*;publicclasstestThrows{publicstaticStringreadString()throws
IOException{
int
ch; Stringr="";
booleandone=false;
while(!done){
ch=System.in.read();
if(ch<0||ch==0xd)done=true; else r=r+(char)ch; } returnr;}Enter读入缓冲区的字节总数,如果因为已经到达文件末尾而没有更多的数据,则返回-1。
publicstaticvoidmain(Stringargs[]){ Stringstr; try{
str=readString(); }catch(IOExceptione){
System.out.println("产生了输出/输出异常"); return; }
System.out.println("整数是:"+Integer.parseInt(str));}}将字符串转换成整数练习4:阅读程序,说明程序运行的结果。classTC6{staticvoidmathod()throwsIllegalAccessException{
System.out.println("\n在mathod
中抛出一个异常");thrownewIllegalAccessException();}publicstaticvoidmain(Stringargs[]){try{
mathod();}catch(IllegalAccessExceptione){
System.out.println("在main中捕获异常:"+e);}}}没有访问权限程序的运行结果如图所示:练习5:编写程序,在test()方法中使用5/0初始化intTemp,将触发ArithmaticException异常,但test方法不对该异常捕获和处理,而希望调用它的方法对该异常进行捕获和处理。
3.抛出异常的综合实例程序6.11演示了try-catch和throw语句的使用,该程序在KeyboardInput类中定义了两个静态方法ReadInt和ReadDouble,从标准输入设备读取int、double类型数据。首先调用ReadLine方法读取一行字符串,然后将该字符串转换为int、double类型数据。如果在转换的过程中发生错误,输入了错误的数据,则抛掷NumberFormatException类的异常,ReadInt和ReadDouble方法捕捉该异常,然后抛掷Exception异常。ExceptionDemo类在main方法中捕捉异常,调用Exception类的方法getMessage获取错误信息。
例6.8异常处理实例。importjava.io.IOException;classKeyboardInput{ staticint
ReadInt()throwsException { Stringstr=ReadLine(); try{ returnnewInteger(str).intValue(); //将读入的字符串转换为int}catch(NumberFormatExceptione){ thrownewException("输入数据错误"); } }
staticdoubleReadDouble()throwsException{ Stringstr=ReadLine(); try{ returnnewDouble(str).doubleValue();//将读入的字符串转换为double}catch(NumberFormatExceptione){ thrownewException("输入数据错误"); } }
staticStringReadLine() { charin; Stringinputstr=""; try{in=(char)System.in.read(); while(in!='\n'){ if(in!='\r')
inputstr=inputstr+in; in=(char)System.in.read(); } }catch(IOExceptione){
inputstr=""; }returninputstr; }}\n表示回车\r表示换行publicclassExceptionDemo{ publicstaticvoidmain(String[]args) { try{
System.out.println("Theinputdoubleis"+KeyboardInput.ReadDouble());
System.out.println("Theinputintegeris"+KeyboardInput.ReadInt()); }catch(Exceptione){
System.out.println(e.getMessage()); } }}classTC7{staticvoidmathodA(){try{
System.out.println("\nmathodA
抛出一个异常");thrownewRuntimeException();}finally{
System.out.println("执行mathodA
的finally");}}练习6:阅读程序,说明程序运行的结果。staticvoidmathodB(){try{
System.out.println("mathodB
正常返回");return;}finally{
System.out.println("执行mathodB
的finally");}}publicstaticvoidmain(Stringargs[]){try{
mathodA();}catch(Exceptione){mathodB();}}}程序的运行结果如图所示:上例中finally子句的执行顺序说明:当一个异常被抛出时,程序的执行就不再是连续的了,会跳过某些语句,甚至会由于没有与之匹配的catch子句而过早地返回。有时要确保一段代码不管发生什么异常都能被执行是必要的,finally子句就是用来标识这样一段代码的。即使没有catch子句,finally语句块也会在执行了try语句块后立即被执行。每个try语句至少都要有一个与之相配的catch或finally子句。从一个方法返回到调用它的另外一个方法,或者是通过return语句,或者是通过一个没有被捕获的异常,但finally子句总是在返回前执行。练习7:编写程序,编译时对异常情况的检查不是方法中产生的所有异常错误都必须被捕获或声明,Error和RuntimeException错误就不要求处理。Error属于严重的系统错误,没有办法在程序中处理。而RuntimeException在运行时应该在编写程序中避免发生错误。对于非运行时异常,则要求必须捕获或声明。也就是说,要么通过try-catch语句捕获,要么将这些异常放在方法的throws语句中声明,否则无法通过编译。子类方法抛出的异常只能是父类方法抛出异常的同类或子类。也就是说,子类不能抛出比父类更多的异常。
6.3自定义异常类在选择要抛出异常类型时,不一定非要使用Java平台提供的异常类,更多的情况下是抛出程序员自己创建的异常,以满足对某些特定应用环境下的异常处理需要。这就涉及异常的创建问题,即创建自己的异常。自定义异常类的格式:自定义异常类型是从Exception类中派生的,所以要使用下面的声明语句来创建:
<class><自定义异常名><extends><Exception>{…}用户定义异常类是通过派生Exception类来创建的,这种异常类可以包含一个“普通”类所包含的任何东西。下面就是一个用户定义异常类的例子,它包含一个构造函数、几个变量以及方法。例如:
classMyExceptionextendsException{privateint
ErrorCode;
MyException(int
ecode){super("自定义的异常类型");
ErrorCode=ecode;}publicint
getErrorCode(){ returnErrorCode;}}
定义上面的异常类后可以通过下面的语句抛掷MyException类的异常:thrownewMyException(1);通过继承Exception类或它的子类,实现自定义异常类;对于自定义异常,必须采用throw语句抛出异常,这种类型的异常不会自行产生。总体上分为两步:第1步:定义异常类。第2步:定义异常对象,并抛出该对象。第1步:定义异常类。例如:classuserExceptionextendsException{
intn=0;//计数器
userException(){n++; }
userException(Strings){ super(s); n++; }
Stringshow(){return"自定义异常对象:"+n; }}第2步:定义异常对象,并抛出该对象。例如:publicclasstestException{ staticvoidTest()throwsuserException{
userExceptione; e=newuserException("自定义异常"); throwe;
//=thrownewuserException("自定义异常"); } publicstaticvoidmain(Stringargs[]){ try{ Test(); }catch(userExceptione){
System.out.println(e.show()); } }}练习7:阅读程序,说明程序运行的结果。<=0)}}例6.12异常类的定义、异常抛郑和捕捉。程序运行后从键盘输入10个英文字母,如果输入非英文字母的字符,则抛掷自定义的notLetterException类型的异常。
importjava.io.IOException;
classnotLetterExceptionextendsException{ //异常类定义
publicnotLetterException(){ super("NotanEnglishletter"); }}publicclassgetLetter{ voidReadLetter(char[]s)throwsnotLetterException,IOException{ charc;
for(inti=0;i<s.length;i++){ c=(char)System.in.read(); if((c>='A'&&c<='Z')||(c>='a'&&c<='z')) s[i]=c; elsethrownewnotLetterException();//异常的抛掷
} }
publicstaticvoidmain(String[]args) { char[]s=newchar[10];
getLetterg=newgetLetter(); try{
g.ReadLetter(s); }catch(notLetterExceptione){//捕捉自定义的异常
System.out.println(e.getMessage()); }catch(IOExceptione){
System.out.println("I/Oerror"); } }}练习8:编写程序,程序的运行结果如下图。classMyExceptionextendsException{privateintx;
MyException(inta){x=a;}publicStringtoString(){return"MyException";}}publicclassTC8{staticvoidmathod(inta)throwsMyException{//声明方法会抛出MyException
System.out.println("\t此处引用mathod("+a+")");if(a>10)thrownewMyException(a);//主动抛出
System.out.println("正常返回");}
publicstaticvoidmain(Stringargs[]){try{
System.out.println("\n进入监控区,执行可能发生异常的程序段");mathod(8);mathod(20);mathod(6);}catch(MyExceptione){
System.out.println("\t程序发生异常并在此处进行处理");
System.out.println("\t发生的异常为:"+e.toString());}
System.out.println("这里可执行其它代码");}}
异常处理常用调试方法
在程序中增加输出变量的信息。例如:System.out.println("x="+x);通过this输出当前对象的状态。例如:System.out.println(“对象:”+this);用printstackTrace()输出异常对象的调用栈;用getMessage()方法获取异常信息;用getClass()和getName()获取异常类名。classuserExceptionextendsException{ publicuserException(){ super("自定义异常"); }}
publicclassgetMessages{ publicstaticvoidm1()throwsuserException{ m2(); } publicstaticvoidm2()throwsuserException{ thrownewuserException(); }例6.13异常处理的常用调试方法。publicstaticvoidmain(Stringargs[]){try{ m1();}catch(userExceptione){
System.out.println(e.getMessage());
e.printStackTrace();
System.out.println(“异常类型:”+
e.getClass().getName()); } }}程序输出结果:自定义异常userException:自定义异常
atgetMessages.m2(getMessages.java:13)atgetMessages.m1(getMessages.java:10)atgetMessages.main(getMessages.java:19)异常类型:userException
异常处理的注意内容
当一个异常一直传递到main方法(程序调用的最高层)还没有被捕获,那么JVM将捕获该异常并给出相应的异常信息且中止引发异常之后的操作,这对于用户来说实际上就是程序已经崩溃。因此自定义的异常类名不宜放在main方法声明时的throws列表中。Catch子句不能图方便只写catch(Exceptione){}。因为它将捕获所有的异常,实际上无法给用户提供实质性的异常提示信息,也不便于程序调试。编写程序时对异常的处理与不处理的区别在于我们是否能够控制所有的操作。例6.14比较两个程序的运行结果。
publicclassA{publicstaticvoidmain(String[]args){
intb=0;b=12/0;//对异常不处理
System.out.println(“b=”+b);}}执行结果:Exceptioninthread“main”java.lang.ArithmeticException:/byzeroatA.main<A.java:4>
publicclassA{publicstaticvoidmain(String[]args){
intb=0;try{b=12/0;//对异常进行处理
}catch(ArithmeticExceptione){
e.printStackTrace(System.err);}
System.out.println(“b=”+b);}}执行结果:Java.lang.ArithmeticException:/byzeroatA.main<A.java:5>b=06.4编程实例程序6.14实现了一个简易的计算器,该程序由两个文件组成。文件Calculator.java中定义了一个类Calculator,该类用于实现计算器的功能,但不包括输入输出。文件AppCal.java中定义了类AppCal,其中包含main方法。AppCal的run方法从键盘接收输入,调用Calculator的方法进行处理。例如,若从键盘输入3+2*3,则程序按照输入的顺序计算,最后输出结果15。【程序6.14】简易计算器。//Calculator.javapublicclassCalculator{ privateintstatus=0;//计算器当前状态
//0表示将已计算结果放入操作数1,等待运算符,或重新输入操作数
//1表示正在输入操作数1 //2表示已输入运算符,等待输入操作数2 //3表示正在输入操作数2
privateStringnum1="0",num2="";//存储运算数
privatecharOp;//存储运算符
publicStringDisplayStr="0";//存储运算结果
//计算器回到初始状态
publicvoidinit() { status=0; num1="0";
DisplayStr="0"; }
//处理一个按键
voidKeyProcess(charkey){ switch(status){ case0:
if((key>='0'&&key<='9')||key=='.'){ status=1; num1=""+key;
DisplayStr=num1; } elseif(key=='+'||key=='-'||key=='*'||key=='/'){ Op=key; status=2;} break;
case1: if((key>='0'&&key<='9')||key=='.'){ status=1; num1=num1+key;
DisplayStr=num1; } elseif(key=='='){status=0; } elseif(key=='+'||key=='-'||key=='*'||key=='/'){ Op=key; status=2; } break;
case2: if((key>='0'&&key<='9')||key=='.'){ status=3; num2=""+key;
DisplayStr=num2; } elseif(key=='='){ status=0; } break;
case3: if((key>='0'&&key<='9')||key=='.'){ num2=num2+key;
DisplayStr=num2; } elseif(key=='='){ Cal();
DisplayStr=num1; status=0; }elseif(key=='+'||key=='-'||key=='*'||key=='/'){ Cal();
DisplayStr=num1; status=2; Op=key; } break; } }//计算结果
voidCal() { doublen1=newDouble(num1).doubleValue();//使用Double
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 企业防中暑应急预案(10篇)
- 幼儿演讲稿锦集10篇
- 企业财务总监工作总结
- DB12T 598.7-2015 天津市建设项目用地控制指标 第7部分:公益性科研机构项目
- 感恩母亲演讲稿集合五篇
- 学生的实习报告三篇
- 高等数学教程 上册 第4版 习题及答案 P102 第4章 导数的应用
- 影响华法林抗凝效果的药物
- 舞蹈内容课件教学课件
- 部编版历史九年级上册第一单元 第2课《古代两河流域》说课稿
- 電鍍技術資料大全
- 消防电气检验批质量验收记录表(共18页)
- 控轧控冷技术在钢材生产中的应用
- 连接器成本分析-B版
- 金融业不良资产处置法律服务方案书
- 基底节区解剖位置关系.ppt
- 电子商务购物平台的设计与开发论文
- xx大学成人高等教育校外教学点检查自查报告
- 《在政府教育工作督导评估反馈会上的表态发言》
- 交通事故责任划分图例
- 六年级上册数学比的计算题
评论
0/150
提交评论