1、 第五章第五章 Java的异常处理的异常处理为什么要异常处理?v对于任何语言的程序设计而言,错误的发生总是不可避免的对于任何语言的程序设计而言,错误的发生总是不可避免的.v比如说:v 用户输入出错v 所需文件找不到v 运行时磁盘空间不够v 内存耗尽无法进行类的实例化内存耗尽无法进行类的实例化v 算术运算错(数的溢出,被零除)v 数组下标越界 JVMJVM崩溃崩溃v v 当Java程序出现以上的错误时,就会在所处的方法中产生一个异常对象。这个异常对象包括错误的类型,错误出现时程序的运行状态以及对该错误的详细描述。下面我们先看一个简单的例子。v例5.1vpublic class Exception
2、Demo v public static void main(String args)v int x=100;v System.out.println(The result is+x/10);v System.out.println(Divided by zero:+x/0);v当我们对其编译后运行时,其对应的结果如下:v其意思是说,本程序执行到语句“System.out.println(Divided by zero:+x/0)”时,系统会抛出一个例外,该例外在Java中定义为Arithmetic Exception(即属于算术运算例外)。c:jbuilder3javabinjava Exc
3、eption DemoThe result is10Exception in thread main java.lang.Arithmetic Exception:/by zero at Exception Demo.main(Exception Demo.java:5)5.1 什么是异常v异常(异常(ExceptionException)又称为例外,是指在程序)又称为例外,是指在程序运行过程中发生的非正常事件,它会运行过程中发生的非正常事件,它会中断指令的正常执行,影响程序的正常运行。影响程序的正常运行。异常对象v在在JavaJava语言中,我们用异常对象来表示不同语言中,我们用异常对象来表
4、示不同的异常。的异常。v所谓所谓JavaJava异常对象就是一个存放着相关错误异常对象就是一个存放着相关错误信息的对象,如果方法运行时产生了异常,信息的对象,如果方法运行时产生了异常,该方法就可以抛出一个异常对象该方法就可以抛出一个异常对象v为了表示不同种类的异常,为了表示不同种类的异常,JavaJava语言中定义语言中定义了许多异常类。了许多异常类。v异常处理的一般步骤:异常抛出异常抛出异常捕获异常捕获异常处理异常处理5.2 异常处理机制异常处理机制v在Java程序的执行过程中,如果出现了异常事件,就会生成一个异常对象。v生成的异常对象将传递给Java运行时系统,这一异常的产生和提交过程称为
5、抛出(throw)异常。异常处理机制v当Java运行时系统得到一个异常对象时,它将会寻找处理这一异常的代码。找到能够处理这种类型的异常的方法后,运行时系统把当前异常对象交给这个方法进行处理,这一过程称为捕获(catch)异常。v如果Java运行时系统找不到可以捕获异常的方法,则运行时系统将终止,相应的Java程序也将退出。方法的调用堆栈main()main()methodA()methodA()methodB()methodB()methodC()methodC()调调 用用vJavaJava程序在执行的过程中,形成了一个先进后出的程序在执行的过程中,形成了一个先进后出的调用堆栈,各方法之间依
6、照调用先后的不同,由先调用堆栈,各方法之间依照调用先后的不同,由先至后的进入调用堆栈,堆栈的最上层即是当前被调至后的进入调用堆栈,堆栈的最上层即是当前被调用执行的方法。该方法执行完毕后,会将处理器控用执行的方法。该方法执行完毕后,会将处理器控制权交还给调用他的方法,依此类推。制权交还给调用他的方法,依此类推。方法调用堆栈中异常对象的传递 v当某一方法中的一个语句抛出一个异常时,如果该方法中没当某一方法中的一个语句抛出一个异常时,如果该方法中没有处理该异常的语句,那么该方法就会有处理该异常的语句,那么该方法就会中止执行中止执行,并将这个,并将这个异常传递给堆栈中的下一层方法,直到某一方法中含有处
7、理异常传递给堆栈中的下一层方法,直到某一方法中含有处理该异常的语句为止。如果该异常被传递至主方法,而主方法该异常的语句为止。如果该异常被传递至主方法,而主方法中仍然没有处理该异常的语句,则异常将会被抛至中仍然没有处理该异常的语句,则异常将会被抛至JVM,程,程序中断。序中断。main()main()methodA()methodA()methodB()B()methodC()C()调调 用用传传 递递例 程public class ExampleOfException String lines=The first line,The second line,The last line;publi
8、c static void main(String args)ExampleOfException eoe=new ExampleOfException();eoe.methodA();System.out.println(Program finished.);void methodA()methodB();void methodB()methodC();void methodC()for(int i=0;i4;i+)System.out.println(linesi);The first lineThe second lineThe last lineException in thread
9、main java.lang.ArrayIndexOutOfBoundsException:3 at ExampleOfException.methodC(ExampleOfException.java:16)at ExampleOfException.methodB(ExampleOfException.java:12)at ExampleOfException.methodA(ExampleOfException.java:9)at ExampleOfException.main(ExampleOfException.java:6)Java中的异常类v在在JavaJava语言中,任何的异常
10、对象都是语言中,任何的异常对象都是ThrowableThrowable类的类的直接子类或间接子类的实例。直接子类或间接子类的实例。JavaJava的类库已经提供的类库已经提供了一些常见的异常类,如果这些异常类不能够满足了一些常见的异常类,如果这些异常类不能够满足要求,用户也可以创建自己的异常类。要求,用户也可以创建自己的异常类。AWTExceptionThrowableErrorExceptionRuntimeExceptionIOExceptionLinkageErrorVirtualMachineErrorAWTErrorArithmeticExceptionIndexOutOfBound
11、s.InterruptedExceptionFileNotFoundExceptionEOFException.异常(Throwable)分类vError动态链接失败,虚拟机错误等,通常Java程序不应该捕获这类异常,也不会抛出这种异常。vException运行时异常继承于RuntimeException。Java编译器允许程序不对它们做出处理。非运行时异常除了运行时异常之外的其他由Exception继承来的异常类。Java编译器要求程序必须捕获或者声明抛出这种异常。Error类 vErrorError类表示类表示JavaJava运行时产生的系统内部错运行时产生的系统内部错误或资源耗尽等严重错
12、误。误或资源耗尽等严重错误。v这种错误通常是程序无法控制和解决的,如这种错误通常是程序无法控制和解决的,如果发生这种错误,通常的做法是通知用户并果发生这种错误,通常的做法是通知用户并中止程序的执行。中止程序的执行。典型的错误类vNoClassDefFoundErrorvOutOfMemoryErrorvVirtualMachineErrorv。表5.1 Java常见错误列表类 名功 能 描 述ClassCircularityError初始化某类检测到类的循环调用错误ClassFormatError非法类格式错误IllegalAccessError非法访问错误IncompatibleClassC
13、hangError非兼容类更新错误InternalError系统内部错误LinkageError链接错误NoClassDefFoundError运行系统找不到被引用类的定义NoSuchFieldError找不到指定域错误NoSuchMethodError所调用的方法不存在OutofMemoryError内存不足错误UnknownError系统无法确认的错误UnsatisfiedLinkError定义为本地的方法运行时与另外的例程相连接错误VerifyError代码校验错误VirtualMachineError虚拟机出错,可能JVM错或资源不足InstantiationError企图实例化一个接
14、口或抽象类的错误Exception类 vExceptionException的子类表示了不同类型的异常,例的子类表示了不同类型的异常,例如如RuntimeExceptionRuntimeException表示运行时异常,而表示运行时异常,而IOExceptionIOException表示表示I/OI/O问题引起的异常。问题引起的异常。v这些子类也可以被继承以对不同类型的异常这些子类也可以被继承以对不同类型的异常进行细分,如进行细分,如RuntimeExceptionRuntimeException还可细分为还可细分为NullPointerExceptionNullPointerExceptio
15、n、ArithmeticExceptionArithmeticException等;等;IOExceptionIOException还可还可细分为细分为FileNotFoundExceptionFileNotFoundException、EOFExceptionEOFException等。等。典型的异常类vArithmeticExceptionvArrayIndexOutOfBandsExceptionvIOExceptionvFileNotFoundExceptionvNullPointerExceptionvNumberFormatException表5.2 Java常见的一般异常列表 类
16、 名功 能 描 述IllegalAccessException非法访问异常ClassNotFoundException指定类或接口不存在异常CloneNotSupportException对象使用clone方法而不实现cloneable接口IOException输入/输出异常InterruptedIOException中断输入/输出操作异常InterruptedException中断异常(常常应用于线程操作中)EOFException输入流中遇到非正常的EOF标志FileNotFoundException指定文件找不到MalformedURLExceptionURL格式不正确ProtocolE
17、xception网络协议异常SocketExceptionSocket操作异常UnknownHostException给定的服务器地址无法解析UnknownServiceException网络请求服务出错UTFDataFormatExceptionUTF格式字符串转换出错InstantiationException企图实例化接口或抽象类NoSuchMethodException找不到指定的方法表5.3 Java常见的运行异常列表 类 名功 能 描 述ArithmeticException算术运算除数为零IndexOutofBoundException下标越界错误ArrayIndexOutofB
18、oundsException数组元素下标越界错误StringIndexOutofBoundsException字符串下标越界错误ClassCastException类型强制转换异常NegativeArraySizeException数组的长度为负异常NullPointerException非法使用空指针异常NumberFormatException非法数据格式异常IllegalArgumentException非法参数异常IllegalMonitorStateException非法监视器操作异常IllegalThreadStateException非法线程状态异常EmptyStackExcep
19、tion栈空异常,对空栈进行操作NoSuchElementException枚举对象不存在给定的元素异常SecurityException安全性异常必检异常与非必检异常vRuntimeExceptionRuntimeException类及其子类被称为类及其子类被称为“运行运行时异常时异常”一般发生在一般发生在JREJRE内部内部也称也称“非必检异常非必检异常”如如NullPointerExceptionNullPointerExceptionv其他异常被成为其他异常被成为“非运行时异常非运行时异常”一般发生在一般发生在JREJRE外部外部也称也称“必检异常必检异常”如如IOExceptionI
20、OException5.3 异常类的使用v要捕获一个异常,程序员只需要在程序中设要捕获一个异常,程序员只需要在程序中设置一个置一个try/catchtry/catch块,其格式如下:块,其格式如下:trytry 抛出异常的代码抛出异常的代码 catch(catch(某某ExceptionException类型类型 e)e)处理该异常类型的代码处理该异常类型的代码 catch(catch(某某ExceptionException类型类型 e)e)处理该异常类型的代码处理该异常类型的代码 v try捕获异常的第一步是用try选定捕获异常的范围,由try所限定的代码块中的语句在执行过程中可能会生成异
21、常对象并抛出。v catch 每个try代码块可以伴随一个或多个catch语句,用于处理try代码块中所生成的异常事件。catch语句只需要一个形式参数指明它所能够捕获的异常类型,这个类必须是Throwable的子类,运行时系统通过参数值把被抛出的异常对象传递给catch块.在catch块中是对异常对象进行处理的代码,与访问其它对象一样,可以访问一个异常对象的变量或调用它的方法。getMessage()是类Throwable所提供的方法,用来得到有关异常事件的信息,类Throwable还提供了方法printStackTrace()用来跟踪异常事件发生时执行堆栈的内容。异常的捕获过程v当当try
22、try块中的某条代码抛出异常时:首先,自块中的某条代码抛出异常时:首先,自该语句的下一条语句起的所有该语句的下一条语句起的所有trytry块中的剩余块中的剩余语句将被跳过不予执行;其次,程序执行语句将被跳过不予执行;其次,程序执行catchcatch子句进行异常捕获,异常捕获的目的是子句进行异常捕获,异常捕获的目的是进行异常类型的匹配,并执行与所抛出的异进行异常类型的匹配,并执行与所抛出的异常类型相对应的常类型相对应的catchcatch子句中的异常处理代码。子句中的异常处理代码。异常的捕获过程v需要注意的是:如果需要注意的是:如果trytry块中没有任何的异常块中没有任何的异常抛出,则所有的
23、抛出,则所有的catchcatch子句将会被跳过;如果子句将会被跳过;如果trytry块中所抛出的异常对象类型与所有的块中所抛出的异常对象类型与所有的catchcatch子句中的所声明的异常类型都不匹配,子句中的所声明的异常类型都不匹配,则方法会立即中止,并将该异常对象继续抛则方法会立即中止,并将该异常对象继续抛出,沿调用堆栈传递。出,沿调用堆栈传递。examplepublic class ExampleOfException String lines=The first line,The second line,The last line;public static void main(St
24、ring args)ExampleOfException eoe=new ExampleOfException();eoe.methodA();System.out.println(Program finished.);.void methodC()for(int i=0;i10)throw new MyException(a);System.out.println(normal exit);public static void main(String args)try compute(1);compute(20);catch(MyException e)System.out.println(
25、Caught+e);程序运行结果:程序运行结果:called compute(1)called compute(1)normal exitnormal exitcalled compute(20)called compute(20)Caught MyException 20Caught MyException 20异常类的使用v运行时异常则表示由运行时系统所检测到的程序设计问题或者API的使用不当问题,它可能在程序的任何地方出现:(1)对于运行时异常,如果不能预测它何时发生,程序可以不做处理,而是让Java虚拟机去处理它。(2)如果程序可以预知运行时异常可能发生的地点和时间,则应该在程序中进行
26、处理,而不应简单的把它交给运行时系统。异常类的使用(3)在自定义异常类时,如果它所对应的异常事件通常总是在运行时产生的,而且不容易预测它将在何时、何处发生,则可以把它定义为运行时异常,否则应定义为非运行时异常。异常类的使用v积极处理方式:import java.io.*;class ExceptionDemo1public static void main(String args )try FileInputStream fis=new FileInputStream(text);catch(FileNotFoundException e)异常类的使用v消极处理方式:import java.i
27、o.*;class ExceptionDemo1public static void main(String args )throws FileNotFoundException FileInputStream fis=new FileInputStream(text);异常类的使用v如果采用消极处理方式,则由调用该方法的方法进行处理;但是调用该方法的方法也可以采用消极和积极两种处理方式,一直传递到Java运行环境.异常的优点v将错误处理代码与将错误处理代码与“常规常规”代码分离;代码分离;将错误沿调用堆栈传递;将错误沿调用堆栈传递;可以由感兴趣的方法来处理异常可以由感兴趣的方法来处理异常v对
28、错误类型进行分组和区分。对错误类型进行分组和区分。说明的问题v方法也可以不对异常进行捕获而直接将其抛出,并方法也可以不对异常进行捕获而直接将其抛出,并在方法声明中进行说明,那么对方法产生的异常到在方法声明中进行说明,那么对方法产生的异常到底是应该直接进行捕获还是应该将其进行传递呢?底是应该直接进行捕获还是应该将其进行传递呢?v一般来说,对于方法的最终调用者而言,他必须捕一般来说,对于方法的最终调用者而言,他必须捕获并处理该方法抛出的异常。而对于抛出异常的方获并处理该方法抛出的异常。而对于抛出异常的方法而言,应该对方法可能产生的异常进行区分,尽法而言,应该对方法可能产生的异常进行区分,尽量避免一
29、些异常的产生,捕获并处理那些你知道如量避免一些异常的产生,捕获并处理那些你知道如何处理的异常,而对那些你不知道方法的调用者会何处理的异常,而对那些你不知道方法的调用者会如何处理的异常,最好将它们留给方法的调用者进如何处理的异常,最好将它们留给方法的调用者进行处理,这样会增加程序的灵活性。行处理,这样会增加程序的灵活性。说明的问题v需要特别指出的是,虽然异常处理机制为程需要特别指出的是,虽然异常处理机制为程序员提供了非常大的方便,但是作为一个好序员提供了非常大的方便,但是作为一个好的程序员要尽量避免异常的过度使用。这是的程序员要尽量避免异常的过度使用。这是因为:异常对象的实例化和其后续处理工作因
30、为:异常对象的实例化和其后续处理工作是非常消耗资源的,过度的使用异常会明显是非常消耗资源的,过度的使用异常会明显影响程序的执行速度。所以,在使用异常处影响程序的执行速度。所以,在使用异常处理时应该仔细考虑,只对有必要的异常情况理时应该仔细考虑,只对有必要的异常情况使用异常,而不可以将异常泛化。使用异常,而不可以将异常泛化。两段代码的比较代码代码1:try int n=InputReader.inputInteger(请输入一个整数请输入一个整数);if(n1)throw new NumberFormatException();catch(NumberFormatException e)Syst
31、em.out.println(输入范围错误!输入范围错误!);代码代码2:int n=InputReader.inputInteger(请输入一个整数请输入一个整数);if(n1)System.out.println(输入范围错误!输入范围错误!);v代码代码1 1采用了异常处理方式;代码采用了异常处理方式;代码2 2则通过对用户输入的分则通过对用户输入的分析避免了异常的使用,提高了代码效率。析避免了异常的使用,提高了代码效率。问题下面的代码合法吗?下面的代码合法吗?try.finally.下面的代码可以捕获何种异常?使用这种异常处理器有什么问下面的代码可以捕获何种异常?使用这种异常处理器有什
32、么问题?题?catch(Exception e).问题下面的处理器可以捕获什么异常?下面的处理器可以捕获什么异常?catch(Exception e).catch(ArithmeticException a).这个异常处理器中有错误吗?此代码能否被编译?这个异常处理器中有错误吗?此代码能否被编译?问题public static void cat(File named)RandomAccessFile input=null;String line=null;try input=new RandomAccessFile(named,“r”);while(line=input.readLine()!=null System.out.println(line);return;finally if(input!=null)input.close();