- 第一卷
- 第二卷
当在Java程序中发生一个错误时,例如:一个变元的值非法,代码会发现这个错误,并引发一个异常(exception)。在缺省的情况下,异常会输出一个错误消息,然后中止线程的执行。但是,程序自己可以定义异常处理段(exceptionhandler)来截获(catch)异常,并从错误中恢复。有一?copy;异常是由Java解释器在运行时刻引发的。实际上,任何类都可以定义属于自己的异常,并使用throw语句引发它们。一个throw(引发?copy;语句是由throw关键字和一个对象构成。按常规,该对象应该是Exception类的实例或其子类的实例。throw语句会引起执行转向相应的异常处理段。当一个throw语句执行时,它下面的所有代码不再执行了,它所在的方法也不再返回值。下面的例子将演示如何创建一个Exception的子类,然后引发一个异常。
classMyExceptionextendsException{}
classMyClass{
voidoops(){
if(/*不出现错误*/){…}
else{/*出错*/}
else{/*出错*/thrownewMyException();}
}
}
为了定义一个异常处理段,程序必须用try语句把可能产生异常的代码成组。在try语句后面跟上一个或多个catch(截获?copy;语句,每个异常对应一个catch语句。每个catch语句中包含着异常处理段。例如:
try{p.a=10;}
catch(NullPointerExceptione){
println(\"pwasnull\");
}
catch(Exceptione){
println(\"othererrorsoccured\");}
catch(Objectobj){
println(\"Whothrewthatobject?\");
}
catch语句和一个方法定义类似,只不过该方法只有一个参数,且无返回类型。参数可以是一个类或一个界面。当一个异常发生时,嵌套的try/catch语句会寻找出与该异常类相匹配的参数。如果一个参数和指定异常匹配则:该参数和指定的异常是同一个类,或该参数是指定异常的子类,或*如果参数是一个界面,指定异常类实现了这个界面。第一个参数和异常匹配的try/catch语句,则与其匹配的catch语句执行。在catch语句执行完后,程序的执行被恢复。但已不可能恢复到异常发生处再次执行。例如:
print(\"now\");
try{print(\"is\");
thrownewMyException();
print(\"a\");
}catch(MyExceptione){
print(\"the\");
}print(\"time\\n\");
打印为"nowisthetime"。正如这个例子所示,异常应该主要用于错误处理,若用于其它方面会使代码晦涩难?reg;。异常处理段是可以嵌套的,允许异常处理可以发生在多个地方。嵌套异常处理通常用于当第一个处理程序无法完全从错误中恢复过来的时候,而不得不执行一?copy;清除代码。为了把异常处理控制传递给更高层的处理段,可以再一次对截获对象实?copy;throw操作。注要再次实throw异常的方法,throw语句执行完后,会终止执行。
try{f.open();}
catch(Exceptione){
f.close();throwe;
}
定局语句finally(定局?copy;语句是用于保证无论在异常是否发生的情况下,某?copy;代码被执行。下例说明finally语句的用法:
try{//做某?copy;动作;}
finally{//此后清除;}
和以下代码类似
try{//做某?copy;动作}
catch(Objecte){
//此后清除;throwe;
}
}//此后清除;
即使try块中包含return,break,continue,throw语句,finally语句也会被执行。例如:下面的代码"finally"总是被输出,而"aftertry"仅在a!=10时被输出。
try{if(a==10){return;}}
finally{print(\"finally\\n\");}
print(\"aftertry\\n\");
运行时刻异常本节列出的清单是Java解释器引发的各种异常。当运行时刻发现各种错误,由解释器引发异常。ArithmeticException如果程序试图除0,或用0取模,会产生ArithmeticException(算术异常?copy;,其它算术操作不会产生异常。有关Java如何处理其它算术错误的信息,见"整数运算符"和"浮点运算符"两节。例如: 下面的代码将会引发ArithmeticException异常:
classArith{
publicstaticvoidmain(Stringargs[]){
intj=0;j=j/j;
}
}
NullPointerException当程序试图访问一个空对象中的变量或方法,或一个空数组中的元素时则引发NullPointerException(空指针异常?copy;。例如,访问长度为0的数组a[0]。有以下类声明,运行时会引发NullPointerException异常:
classNull{
publicstaticvoidmain(Stringargs[]){
Stringo=null;inta[]=null;o.length();a[0]=0;
}
}
有趣的是,如果我们引发一个空对象,也会产一NullPointerException异常。IncompatibleClassChangeException当一个类的定义被改变,而引用该类的其它类没有被重新编译时,会产生这一异常。有四种类更改会导致运行时刻引发IncompatibleClassChangException异常。*一个类中的变量声明由static变成非static,而其它访问该类这一变量的类没有被重新编译。*一个类中的变量声明由非static变成static,而其它访问该类这一变量的类没有被重新编译。*类中声明的某个域被删除,而其它访问该域的类没有被重新编译。*类中声明的某个方法被删除,而其它访问该方法的类没有被重新编译。 ClassCastException如果试图把对象o强制成ClassC,而o既不是ClassC的实例,也不是ClassC子类的实例,这时便会产生ClassCastException。
classClassCast{
publicstaticvoidmain(Stringargs[]){
Objecto=newObject();
Strings=(string)o;s.length();
}
}
}
NagativeArraySizeException如果一个数组的长度是负数,则会引发NagativeArraySizeException(数组负下标?copy;异常。例如下面类定义的代码在运行时引发这一异常:
classNegArray{
publicstaticvoidmain(Stringargs[]){
inta[]=newint[-1];
a[0]=0;
}
}
OutOfMemoryException当系统无法再向应用程序提?copy;内存时,会引发OutOfMemoryException(内存溢出?copy;异常。这种异常只能出现在创建新对象的时候,即new被调用的时候。例如,下面一段代码在运行时刻会引发OutOfMemoryException异常:
classLink{
inta[]=newint[1000000];
Linkl;
}
ClassOutOfMem{
publicstaticvoidmain(Stringargs[]){
publicstaticvoidmain(Stringargs[]){
Linkroot=newlink();
Linkcur=root;
while(true){
cur.l=newLink();cur=cur.l;
}
}
}
NoClassDefFoundException如果一个类被引用,但在运行时刻,系统没有找到被引用的类,这时会引发NoClassDefFoundException(未找到类定义?copy;异常。例如,NoClass 的声明如下:
classNoClass{
publicstaticvoidmain(Stringargs[]){
Cc=newC();
}
}
当NoClass运行时,如果解释器找不到C类,则会产生NoClassDefFoundException。注意,在NoClass被编译时C类一定要存在。
IncompatibleTypeException如果试图为一界面作实例,则会引发IncompatibleTypeException(类型不兼容?copy;异常。例如,下面的代码会引发一个IncompatibleTypeException。
InterfaceI{}
classIncompType{
publicstaticvoidmain(Stringargs[]){
Ir=(I)new(\"I\");
}
}
ArrayIndexOutOfBoundsException试图访问数组中的一个非法元素时,会引发ArrayIndexOutOfBoundsException(数组索引越界?copy;异常。例如:
ClassArrayOut{
publicstaticvoidmain(Stringargs[]){
inta[]=newint[0];
a[0]=0;
}
}
publicstaticvoidmain(Stringargs[]){
inta[]=newint[0];
a[0]=0;
}
}
UnsatisfiedLinkException如果一个方法被声明为本机,但该方法在运行时刻却不能连接到一个例程体上去时,会产生UnsatisfiedLinkException(无法连接?copy;异常。例如:
ClassNoLink{
staticnativevoidfoo();
publicstaticvoidmain(Stringargs[]){
foo();
}
}
InternalExceptionInternalException(内部?copy;异常是不能被引发的。只有在运行失败作一致性检查时,才会引发这个异常。