JAVA教程全集电子版下.docx
《JAVA教程全集电子版下.docx》由会员分享,可在线阅读,更多相关《JAVA教程全集电子版下.docx(19页珍藏版)》请在冰豆网上搜索。
JAVA教程全集电子版下
第9章异常处理
一般来说,程序在运行过程中各种情况都有可能发生,出现错误是难免的,有些错误是不可挽救的,如系统崩溃、电源故障等;而大多数错误是可以避免的,如要求的设备没有准备好、读取的文件不在指定的目录中等等。
程序设计人员应预先估计可能出现错误的情况,并针对这些情况在程序中进行相应的处理。
这在Java中被称为异常处理。
在本章中,我们将主要介绍异常类和异常处理。
9.1异常
任何一个程序,我们都不能说它是绝对安全的、正确无误的。
因为除了那些明显可能造成的错误外,输入错误、不可预见的条件错误和大量的运行环境所造成的错误等等。
尤其,Java是一个网络编程的语言,网络中可能出现不可预见的情况更多一些,例如,一个用户、10个用户、100用户访问一个应用系统可能是正常的,但更多的用户访问它就有可能不正常了。
要保证程序的质量,就必须在程序中处理可能发生的各种错误。
所谓异常(Exception)又被称之为例外,就是指在程序运行过程中可能会发生的各种各类的错误,如系统类异常、运算类异常(数组下标越界、除数为零、算术溢出(即超出了数值的表达范围)等)、I/O类异常、网络类异常等等。
为了处理异常,Java中定义了很多异常类,每个异常类代表了一种运行异常,类中定义了程序中可能遇到的异常条件及异常信息等内容。
下边简要介绍一下异常类及异常处理机制。
9.2异常类
Java使用错误或异常来指示处理程序时出现错误的情况,java.lang包中的Throwable类及其子类定义了Java程序中可能发生的错误和异常。
其类的层次结构如下:
|-java.lang.Throwable
|-java.lang.Error
|-java.lang.AssertionError
|-java.lang.LinkageError
……………………
|-java.lang.ThreadDeath
|-java.lang.VirtualMachineError
………………………
|-java.lang.Exception
|-java.lang.ClassNotFoundException
|-java.lang.CloneNotSupportedException
|-java.lang.IllegalAccessException
|-java.lang.InstantiationException
|-java.lang.InterruptedException
|-java.lang.NoSuchFieldException
|-java.lang.NoSuchMethodException
|-java.lang.RuntimeException
|-java.lang.ArithmeticException
|-java.lang.ArrayStoreException
|-java.lang.ClassCastException
|-java.lang.EnumConstantNotPresentException
|-java.lang.IllegalArgumentException
|-java.lang.IllegalThreadStateException
|-java.lang.NumberFormatException
|-java.lang.IllegalMonitorStateException
|-java.lang.IllegalStateException
|-java.lang.IndexOutOfBoundsException
|-java.lang.ArrayIndexOutOfBoundsException
|-java.lang.StringIndexOutOfBoundsException
|-java.lang.NegativeArraySizeException
|-java.lang.NullPointerException
|-java.lang.SecurityException
|-java.lang.TypeNotPresentException
|-java.lang.UnsupportedOperationException
从上边类的层次结构可以看出,Throwable类是所有错误(Error)和异常(Exception)类的父类。
Error及其子类定义了系统或运行环境所产生的错误,所谓错误,一般都是严重的问题。
在程序的运行中,它的产生是不可预料的,即便知道错误产生了,也没有办法去处理它。
这是一类在程序中不应该也不能够捕捉和处理的错误。
因此本章对它不作介绍。
Exception及其子类定义了所有常规的异常,这类异常发生的几率相对较高。
事实上,我们也可把它划分为两种,一种是Java编译器在编译生成类代码时发现错误所产生的异常,这种异常大家都遇到过,也都处理过,也就是按照异常显示的出错信息和出错行,修改程序再进行编译就是了;另一种是在程序运行过程中发生错误而产生的异常。
我们在程序中要捕捉和处理的就是这种异常。
下边我们先介绍一下Throwable类的功能。
1.构造方法
构造Throwabl对象的方法如下:
1)publicThrowable()创建一个新对象,详细消息为null。
2)publicThrowable(Stringmessage)创建一个新对象,详细消息为message。
3)publicThrowable(Stringmessage,Throwablecause)创建一个新对象,详细消息为message和cause。
与cause相关的消息不是被自动合并到新对象的详细消息中来的。
4)publicThrowable(Throwablecause)创建一个新对象,详细消息为cause。
2.方法
Throwable类提供的方法如下:
1)publicStringgetMessage()返回此对象的详细消息字符串。
2)publicStringgetLocalizedMessage()返回对象的本地化描述。
默认同getMessage()。
3)publicThrowablegetCause()返回对象的cause,如果cause不存在或未知,则返回null。
4)publicStringtoString()返回对象的简短描述。
如果对象的详细消息非空,则结果的格式是:
此对象的实际类名:
对象的getMessage()方法的结果;否则只返回此对象的实际类名。
5)publicvoidprintStackTrace()将此对象及其追踪输出至标准错误流。
6)publicvoidprintStackTrace(PrintStreams)将此对象及其追踪输出到输出流s。
7)publicvoidprintStackTrace(PrintWriters)将此对象及其追踪输出到PrintWriter对象s。
8)publicThrowablefillInStackTrace()在异常堆栈跟踪中填充,在对象信息中记录有关线程堆栈帧的当前状态。
返回对象的引用。
9)publicStackTraceElement[]getStackTrace()提供编程访问由printStackTrace()输出的堆栈跟踪信息。
返回堆栈跟踪元素的数组,每个元素表示一个堆栈帧。
10)publicvoidsetStackTrace(StackTraceElement[]stackTrace)设置由getStackTrace()返回的并由printStackTrace()和相关方法输出的堆栈跟踪元素。
此方法设计用于RPC框架和其他高级系统。
上边列出了Throwable类的方法。
在其子类中,一般没有提供什么方法,它们主要是继承了父类的这些方法。
因此对子类不再一一介绍,用到时简要说明一下,要了解更多的信息请参阅相关的JDK文档。
9.3异常处理
在Java程序运行过程中如果发生了错误,系统就会产生一个与该错误相对应的异常类的对象,产生异常类对象的过程被之为异常的抛出。
如果要对异常进行处理,就必须在程序中对抛出的异常进行捕捉并安排相应的代码处理异常。
9.3.1抛出异常
一般来说,抛出异常有两种方式:
一是系统自动抛出异常,如系统在运行过程中遇到了异常,如空对象的引用(NullPointerException)、数组元素引用中下标超出边界(IndexOutOfBoundsException)等等;二是程序开发者根据设计要求在程序中主动创建异常对象,通过该对象的抛出告诉方法的调用者遇到了异常。
下边简要介绍一下在程序中抛出异常的语句。
1.throw语句
throw语句用于在方法的内部抛出异常对象。
其语句的一般格式如下:
thow异常类对象;
该语句一般用于自定义异常的抛出。
我们将在后边介绍自定义异常。
2.Throws子句
如果知道在一个方法中会产生异常,但并不确切知道如何对异常进行处理或无需对异常进行处理时,可以在定义方法时声明可能会引发的异常。
定义方法抛出异常的一般格式是:
[访问限定符][修饰符][类型]方法名(声明形参列表)throws异常列表
在有些情况下,我们只需抛出异常,并不需要去捕获或处理这些异常。
比如下边的一个例子。
例9.1从键盘上输入26个字母a~z并输出对应的ascii码值。
/*这是一个输出a~z26个字母对应的ascii码值的程序
*程序的名称:
ExceptionExam9_1.java
*目的是演示抛出异常的用法
*/
importjava.io.*;
publicclassExceptionExam9_1
{
publicstaticvoidmain(String[]args)
{
int[]bt=newint[26];
System.out.println("请请按照顺序输入26个字母:
");
for(inti=0;iSystem.out.println("a~z对应的ascii编码是:
");
for(inti=0;i{
if(i%6==0)System.out.println();
System.out.print((char)bt[i]+"="+bt[i]+"");
}
}
}
编译该程序会出现如下的错误提示:
D:
\java2007\javaexam\第9章\ExceptionExam9_1.java:
13:
unreportedexceptionjava.io.IOException;mustbecaughtordeclaredtobethrown
for(inti=0;i^
1error
从出错信息可以看出,由于涉及到系统标准设备(键盘)的输入,所以系统要求在程序中捕捉或说明要抛出的java.io.IOException异常。
这是在编译过程中由编译系统抛出的异常,根据异常信息的提示,修改程序加入抛出java.io.IOException异常即可,由于该异常无法用程序代码进行处理,所以我们可以在方法声明上说明引发该异常:
publicstaticvoidmain(String[]args)throwsIOException
在对程序做了上述修改之后,编译并执行程序,输入26个字母,执行结果如图9-1所示。
图9-1例9.1执行屏幕
在网络程序中,涉及到网络引发的异常,诸如远程方法调用等,一般都采用在定义方法时声明可能会引发的异常。
9.3.2异常的处理
如上所述,在程序运行过程中,一旦遇到错误就会抛出相应的异常,那么如何在程序中对需要处理的异常进行捕捉处理呢?
Java提供了try~catch~finally语句块的结构,对程序中抛出的异常进行捕捉处理。
该结构的一般格式如下:
try
{
语句块//可能产生异常的代码段
}
catch(异常类型,参数)
{
语句块//异常处理代码段
}
[catch(异常类型1,参数1)
{
语句块//异常处理代码段
}
……………………………
catch(异常类型n,参数n)
{
语句块//异常处理代码段
}]
[finally
{
语句块//不论异常是否发生,均应执行的代码段
}]
其中:
1)try代码块中应包含可能引发一个或多个异常的代码。
所希望捕捉的可能会引发异常的语句代码必须放在该块中。
2)catch代码块包含着用于处理一个由try块中抛出的某一特定类型异常的代码段。
try块中可能会抛出多个异常,要捕捉并处理这些异常,就需要对应有多个catch代码块。
每一个catch代码块只能对应处理一类异常。
3)finally代码块总是在方法结束前执行。
往往会出现这样的情况,由于异常总是立即抛出的,出现异常后程序也会从抛出异常的位置跳出try块,该位置下边剩余的代码没有被执行,这可能会带来一些问题。
比如,已经打开了一个文件,但关闭文件的代码未被执行,在没有关闭文件的情况下退出,有可能会造成文件的损害或数据的丢失。
finally块中的代码就是来处理类似问题的。
我们先看下边一个示例。
例9.2产生两组10以内的随机整数放入一维数组a,b中,然后输出b[i]/(a[i]-b[i])的对应值。
我们先看一下没有对异常进行捕捉处理的程序代码:
/*这是一个处理算术运算异常的程序
*程序的名称:
ArithmerticExceptionExam9_2.java
*目的是演示抛出异常的用法
*/
importjava.util.*;
importjava.lang.ArithmeticException.*;
publicclassArithmeticExceptionExam9_2
{
publicstaticvoidarithmetic(int[]a,int[]b)
{
intm;
for(inti=0;i{
m=b[i]/(a[i]-b[i]);
System.out.print("i="+i+"时m="+m+"||");
}
}
publicstaticvoidmain(String[]args)
{
int[]bt=newint[10];
int[]at=newint[10];
Randomrda=newRandom(9876);//定义创建随机数对象rda
Randomrdb=newRandom(2341);//定义创建随机数对象rdb
for(inti=0;i{
bt[i]=rda.nextInt(10);//产生一组10以内的随机整数
at[i]=rdb.nextInt(10);//产生一组10以内的随机整数
}
arithmetic(at,bt);//调用运算方法
}
}
编译并运行程序,可能会出现如如图9-2这样的结果:
图9-2例9-2没有捕捉错误的执行结果
从上边的结果我们可以看出,在arithmetic()方法中,执行循环运算时,只执行了两次,第三次便发生了异常,程序随之也中止了。
下边我们修改arithmetic()方法,加入异常处理结构的语句:
publicstaticvoidarithmetic(int[]a,int[]b)
{
intm;
for(inti=0;itry
{
m=b[i]/(a[i]-b[i]);
System.out.print("i="+i+"时m="+m+"||");
}
catch(ArithmeticExceptione)
{
System.out.println("\ni="+i+"时出现异常:
"+e.toString());//如果除数为0则显示信息
}
}
再次编译和运行程序,可以看到如图9-3的运行结果,由于添加了捕捉处理的结构语句块,在程序中执行arithmetic()方法时,循环到第三遍发生了异常,程序捕捉了该异常并进行了输出相关信息的处理,处理之后程序继续运行。
一般来说,当我们认为异常并不严重,可以继续程序的执行时,通常不会做出立即结束程序的处理。
图9-3例9-2捕捉错误之后的执行结果
下面再给出一个捕捉和处理数组下标超界的简单示例。
例9.3产生一组(10个)100以内的随机数放入一维数组中,然后随机产生下标并显示其值。
程序代码如下:
/*这是一个处理数组越界异常的程序
*程序的名称:
ArrayIndexOutOfBoundsExam9_3.java
*目的是演示抛出异常的用法
*/
importjava.util.*;
importjava.lang.*;
publicclassArrayIndexOutOfBoundsExam9_3
{
publicstaticvoidmain(String[]args)
{
int[]a=newint[10];
Randomrda=newRandom();//定义创建随机数对象rda
for(inti=0;i<10;i++)a[i]=rda.nextInt(100);//产生一组100以内的随机整数
for(inti=1;i<6;i++)
{
intd=rda.nextInt(15);//生成15以内的随机下标
try
{
System.out.println("a["+d+"]="+a[d]);//显示元素值
}
catch(ArrayIndexOutOfBoundsExceptione)
{
System.out.println(d+">=10,超出了可获取的下标范围!
!
!
");
}
}
}
}
编译运行程序,执行结果如图9-4所示。
图9-4例9.3执行结果
由于是随机产生下标,每次的运行结果可能会不一样。
9.4用户自定义异常类
上边介绍了Java中定义的标准异常类,但是有时候我们希望当一个标准异常出现时添加信息;或者对于一些特殊的应用,代码中需要一些出错条件以明确区分出某种特定的异常。
在这些情况下,我们可以定义自己的异常类并创建异常对象来处理自己程序中的运行错误。
用户自定义异常类必须以Throwable作为超类,即它必须是Throwable类的子类(直接或间接),尽管可以从任何一个标准异常类派生出自定义异常类,但最好还是从Exception异常类派生。
下边我们举一个例子简要说明一下自定义异常类的定义与应用。
在前边我们已经介绍过学生成绩录入程序,如果要建立一个异常类,当输入的成绩不是规定范围内的数据时,引发该异常。
下边先定义异常类。
例9.4定义异常类ResultOutOfBoundsException。
程序参考代码如下:
/*这是一个定义成绩超出规定范围的异常类
*类名是:
ResultOutOfBoundsException
*/
publicclassResultOutOfBoundsExceptionextendsException
{
ResultOutOfBoundsException()//构造方法
{
super("成绩数据超限错误!
!
!
");
}
publicStringtoString()//返回信息方法
{
return"成绩数据超限错误!
!
!
成绩不能为负值,也不能超出规定的范围!
!
!
";
}
}
该异常类是Exception类的派生类,在类中重写了toString()方法。
在完成异常类的定义之后,下边再定义一个成绩类。
例9.5定义成绩类Result。
程序参考代码如下:
/*这是一个定义学生成绩的类
*类名是:
Result
*/
publicclassResult
{
Stringstudent_no;
intrs1;
Result()//构造方法1
{
student_no="00000000000";
rs1=0;
}//构造方法1结束
Result(Stringno,intr1)//构造方法2
{
student_no=no;
rs1=r1;
}//构造方法2结束
/***定义方法isResult()抛出并引发自定义异常***/
publicbooleanisResult()throwsResultOutOfBoundsException
{
if(rs1<0||rs1>100)
{
thrownewResultOutOfBoundsException();
}
else
{
returntrue;
}
}//方法isResult结束
}
在上边定义的成绩类中,由方法isResult()抛出并引发自定义异常。
下边我们对例8.4的程序做一个修改,测试一下自定义异常的功能。
例9.6修改例8.4,当输入学生的成绩小于0或大于100时,引发异常,对异常进行处理,显示异常信息,并回到成绩栏重新输入。
修改后的程序代码如下:
/*这个程序是对例8.4ExceptionExam9_6.java程序的修改
*程序名为:
ExceptionExam9_6.java
*是一个演示自定义异常的示例程序
*/
importjava.awt.*;
importjava.awt.event.*;
importjavax.swing.*;
publicclassExceptionExam9_6extendsJFrameimplementsActionListener
{
JTextFieldno=newJTextField(10);
JTextFieldresult=newJTextField(10);
JPaneljp=newJPanel();//创建窗格容器摆放相关组件
JTextAreajt=newJTextArea(5,20);//创建多行文本框对象显示学生的相关信息
JScrollPanejs=newJScrollPane(jt);//在滚动容器中显示学生信息
JButtonnext=newJButton("下一个");
JButtonexit=newJButton("退出");
publicExceptionExam9_6()
{
setTitle("成绩录入KeyEvent事件演示");
ContainerrootPane=thi