本文由好心情3721贡献
Generated by Foxit PDF Creator ? Foxit Software http://www.foxitsoftware.com For evaluation only.
保密申明:秘密级
iCarnegie Java 教材 版本:1.0
作者: 审批:
Daniel Zhang
日期: 日期:
Generated by Foxit PDF Creator ? Foxit Software http://www.foxitsoftware.com For evaluation only.
保密申明:秘密级
第十章
异 常 处 理
本章介绍Java的异常处理机制。异常(exception)是在运行时代码序列中产生一种异常情 况。换句话说,异常是一个运行时错误。在不支持异常处理的计算机语言中,错误必须被手 工的检查和处理――典型的是通过错误代码的运用等等。这种方法既很笨拙也很麻烦。Java 的异常处理避免了这些问题, 而且在处理过程中, 把运行时错误的管理带到了面向对象的世 界。
10.1
异常处理基础
Java异常是一个描述在代码段中发生的异常(也就是出错)情况的对象。当异常情况发 生,一个代表该异常的对象被创建并且在导致该错误的方法中被引发(throw)。该方法可 以选择自己处理异常或传递该异常。两种情况下,该异常被捕获(caught)并处理。异常可 能是由Java运行时系统产生,或者是由你的手工代码产生。被Java引发的异常与违反语言规 范或超出Java执行环境限制的基本错误有关。 手工编码产生的异常基本上用于报告方法调用 程序的出错状况。 Java异常处理通过5个关键字控制:try、catch、throw、throws和 finally。下面讲述它们 如何工作的。程序声明了你想要的异常监控包含在一个try块中。如果在try块中发生异常, 它被抛出。你的代码可以捕捉这个异常(用catch)并且用某种合理的方法处理该异常。系 统产生的异常被Java运行时系统自动引发。手动引发一个异常,用关键字throw。任何被引 发方法的异常都必须通过throws子句定义。任何在方法返回前绝对被执行的代码被放置在 finally块中。 下面是一个异常处理块的通常形式:
try { // block of code to monitor for errors } catch (ExceptionType1 exOb) { // exception handler for ExceptionType1 } catch (ExceptionType2 exOb) { // exception handler for ExceptionType2 } // ... finally { // block of code to be executed before try block ends }
这里,ExceptionType 是发生异常的类型。下面将介绍怎样应用这个框架。
10.2
异 常 类 型
所有异常类型都是内置类Throwable的子类。 因此, Throwable在异常类层次结构的顶层。 紧接着Throwable下面的是两个把异常分成两个不同分支的子类。一个分支是Exception。该 类用于用户程序可能捕捉的异常情况。 它也是你可以用来创建你自己用户异常类型子类的类。 在Exception分支中有一个重要子类RuntimeException。该类型的异常自动为你所编写的程序 定义并且包括被零除和非法数组索引这样的错误。
Generated by Foxit PDF Creator ? Foxit Software http://www.foxitsoftware.com For evaluation only.
保密申明:秘密级
另一类分支由Error作为顶层, Error定义了在通常环境下不希望被程序捕获的异常。 Error 类型的异常用于Java运行时系统来显示与运行时系统本身有关的错误。 堆栈溢出是这种错误 的一例。本章将不讨论关于Error类型的异常处理,因为它们通常是灾难性的致命错误,不 是你的程序可以控制的。
10.3
未被捕获的异常
在你学习在程序中处理异常之前, 看一看如果你不处理它们会有什么情况发生。 下面的 小程序包括一个故意导致被零除错误的表达式。
class Exc0 { public static void main(String args[]) { int d = 0; int a = 42 / d; } }
当Java运行时系统检查到被零除的情况,它构造一个新的异常对象然后引发该异常。这 导致Exc0的执行停止,因为一旦一个异常被引发,它必须被一个异常处理程序捕获并且被 立即处理。该例中,我们没有提供任何我们自己的异常处理程序,所以异常被Java运行时系 统的默认处理程序捕获。任何不是被你程序捕获的异常最终都会被系统默认处理程序处理。 默认处理程序显示一个描述异常的字符串,打印异常发生处的堆栈轨迹并且终止程序。 下面是由标准javaJDK运行时解释器执行该程序所产生的输出:
java.lang.ArithmeticException: / by zero at Exc0.main(Exc0.java:4)
注意,类名Exc0,方法名main,文件名Exc0.java和行数4是怎样被包括在一个简单的堆 栈使用轨迹中的。还有,注意引发的异常类型是Exception的一个名为ArithmeticException的 子类,该子类更明确的描述了何种类型的错误方法。本章后面部分将讨论,Java提供多个内 置的与可能产生的不同种类运行时错误相匹配的异常类型。 堆栈轨迹将显示导致错误产生的方法调用序列。例如,下面是前面程序的另一个版本, 它介绍了相同的错误,但是错误是在main( )方法之外的另一个方法中产生的:
class Exc1 { static void subroutine() { int d = 0; int a = 10 / d; } public static void main(String args[]) { Exc1.subroutine(); } }
默认异常处理器的堆栈轨迹结果表明了整个调用栈是怎样显示的:
java.lang.ArithmeticException: / by zero at Exc1.subroutine(Exc1.java:4) at Exc1.main(Exc1.java:7)
Generated by Foxit PDF Creator ? Foxit Software http://www.foxitsoftware.com For evaluation only.
保密申明:秘密级
如你所见,栈底是main的第7行,该行调用了subroutine( )方法。该方法在第4行导致了 异常。调用堆栈对于调试来说是很重要的,因为它查明了导致错误的精确的步骤。
10.4
使用try和catch
尽管Java运行时系统提供的默认异常处理程序对于调试是很有用的, 但通常你希望自己 处理异常。这样做有两个好处。第一,它允许你修正错误。第二,它防止程序自动终止。大 多数用户对于在程序终止 运行和在无论何时错误发生都会打印堆栈轨迹感到很烦恼(至少可以这么说)。幸运的是, 这很容易避免。 为防止和处理一个运行时错误,只需要把你所要监控的代码放进一个try块就可以了。 紧跟着try块的后面包括一个说明你希望捕获错误类型的catch子句。完成这个任务很简单, 下面的程序包含一个处理因为被零除而产生的ArithmeticException 异常的try块和一个catch 子句。
class Exc2 { public static void main(String args[]) { int d, a; try { // monitor a block of code. d = 0; a = 42 / d; System.out.println("This will not be printed."); } catch (ArithmeticException e) { // catch divide-by-zero error System.out.println("Division by zero."); } System.out.println("After catch statement."); } }
该程序输出如下:
Division by zero. After catch statement.
注意在try块中的对println( )的调用是永远不会执行的。一旦异常被引发,程序控制由try 块转到catch块。执行永远不会从catch块“返回”到try块。因此, “This will not be printed。” 将不会被显示。一旦执行了catch语句,程序控制从整个try/catch机制的下面一行继续。 一个try和它的catch语句形成了一个单元。catch子句的范围限制于try语句前面所定义的 语句。一个catch语句不能捕获另一个try声明所引发的异常(除非是嵌套的try语句情况)。 被try保护的语句声明必须在一个大括号之内(也就是说,它们必须在一个块中)。你不能 单独使用try。 构造catch子句的目的是解决异常情况并且像错误没有发生一样继续运行。例如,下面 的程序中,每一个for循环的反复得到两个随机整数。这两个整数分别被对方除,结果用来 除12345。最后的结果存在a中。如果一个除法操作导致被零除错误,它将被捕获,a的值设 为零,程序继续运行。
// Handle an exception and move on. import java.util.Random;
Generated by Foxit PDF Creator ? Foxit Software http://www.foxitsoftware.com For evaluation only.
保密申明:秘密级 class HandleError { public static void main(String args[]) { int a=0, b=0, c=0; Random r = new Random(); for(int i=0; i<32000; i++) { try { b = r.nextInt(); c = r.nextInt(); a = 12345 / (b/c); } catch (ArithmeticException e) { System.out.println("Division by zero."); a = 0; // set a to zero and continue } System.out.println("a: " + a); } } }
10.4.1 显示一个异常的描述 Throwable重载toString( )方法(由Object定义),所以它返回一个包含异常描述的字符 串。 你可以通过在println( )中传给异常一个参数来显示该异常的描述。 例如, 前面程序的catch 块可以被重写成
catch (ArithmeticException e) { System.out.println("Exception: " + e); a = 0; // set a to zero and continue }
当这个版本代替原程序中的版本,程序在标准javaJDK解释器下运行,每一个被零除错 误显示下面的消息:
Exception: java.lang.ArithmeticException: / by zero