第 5章 Java例外处理
第 5章 Java例外处理
5.1 异常的基本概念
5.2 异常的处理机制
5.3 异常类的类层次
第 5章 Java例外处理
5.1 异常的基本概念
异常 (Exception)是程序执行过程中出现的非正常事
件, 即各种意外情况 。 比如说:
① 用户输入出错
② 所需文件找不到
③ 运行时磁盘空间不够
④ 内存不够
第 5章 Java例外处理
⑤ 算术运算错 (数的溢出, 被零除 …)
⑥ 数组下标越界
……
当 Java程序出现以上的错误时, 就会在所处的方法
中产生一个异常对象 。 这个异常对象包括错误的类型,
错误出现时程序的运行状态以及对该错误的详细描述 。
下面我们先看一个简单的例子 。
第 5章 Java例外处理
例 5.1
public class ExceptionDemo {
public static void main(String args[]) {
int x=100;
System.out.println("The result is"+x/10);
System.out.println("Divided by zero,"+x/0); } }
第 5章 Java例外处理
当我们对其编译后运行时, 其对应的结果如下:
c:\jbuilder3\java\bin>java Exception Demo
The result is10
Exception in thread "main" java.lang.Arithmetic Exception,/
by zero
at Exception Demo.main(Exception Demo.java:5)
其意思是说,本程序执行到语句,System.out.println
("Divided by zero,"+x/0)”时,系统会抛出一个例外,该
例外在 Java中定义为 Arithmetic Exception (即属于算术
运算例外 )。
第 5章 Java例外处理
5.2 异常的处理机制
我们知道, 一旦程序在执行的过程中出现异常, 往
往有两种处理方式:
(1) 当程序出现错误的时候, 系统将终止程序的运
行, 如例 5.1。 在 Java中这是属于运行异常, 用户不加
干预, 完全交由系统对其进行处理 。
第 5章 Java例外处理
(2) 当程序出现错误时, 采用捕捉-抛出 (catch-
throw)的面向对象编程方式 。 该种方式是当程序运行出
错时, 系统和程序抛出各种标准类型的错误, 程序捕
捉该错误并进行相应处理 。 由于异常均以标准的形式
提供, 使得程序员能以统一的方式对异常进行处理 。
通常, Java的出错与异常处理采用, try,catch,
throws”语句来实现, 下面我们分别加以介绍 。
第 5章 Java例外处理
5.2.1 异常的直接捕获与处理,try-catch
try-catch语句构成 Java对异常直接处理的基本处理单元,
其一般语法如下:
try { program where
… errors may arise
} catch (ExceptionClass1 c) {
what to do with it
} catch (ExceptionClass2 d) {
what to do with it }
第 5章 Java例外处理
上述用法中, 可能出现异常的语句放在由 try语句
所括住的程序块中 。 try块管理其所包含的语句并定义
与之相关的异常指针范围, 它的后面必须至少接一个
catch语句 。 catch语句块负责处理各对应类型的异常 。
实际编程过程中, 如果我们对程序代码可能出现
的异常不进行捕获, Java的编译环境就拒绝执行, 并
要求用户对其作出处理 。 看下例:
第 5章 Java例外处理
例 5.2
import java.io.*;
public class ExceptionDemo1 {
public static void main(String args[]) {
int i;
File Input Stream fis=new File Input Stream("file_in.txt");
第 5章 Java例外处理
File Out put Stream fos=new File Out put
Stream("file_out.txt");
while(i=fis.read())!=-1)
fos.write(i);
fis.close();
fos.close(); } }
例 5.2只是一个简单的文件输入 /输出程序。该程序
中定义了一个文件输入流和文件输出流,然后通过它
们进行文件的拷贝。
第 5章 Java例外处理
当上述程序进行编译的时候, 结果如下:
c:\JBUILD~1\java\bin>javac ExceptionDemo1.java
ExceptionDemo1.java:5,Exception
java.io.FileNotFoundException must be caught,
or it must be declared in the throws clause of this method.
FileInputStream fis=new
FileInputStream("file_in.txt");
^
ExceptionDemo1.java:7,Exception java.io.IOException must
be caught,or it must
be declared in the throws clause of this method.
while((i=fis.read())!=-1)
2 errors
第 5章 Java例外处理
系统异常信息告诉我们, 两种异常程序员必须捕
获, 即 File Not FoundExcetion和 IOException。 对例外进
行处理时, 用户往往想知道异常的具体信息, 我们可
利用异常父类 Throwable中提供的方法 get Message()得
到有关异常事件的信息 。 方法 print Stack Trace()可用来
跟踪异常事件发生时执行堆栈的内容 。 这样, 例 5.2可
改写为
第 5章 Java例外处理
例 5.3
import java.io.*;
public class ExceptionDemo1 {
public static void main(String args[]) {
int i;
try { FileInputStream fis=new
FileInputStream("file_in.txt");
FileOutputStreamfos=new
FileOutputStream("file_out.tx t");
while((i=fis.read())!=-1)
fos.write(i);
第 5章 Java例外处理
fis.close();
fos.close();
}catch (FileNotFoundException e){
System.out.println("The error is:
"+e.getMessage());
e.printStackTrace(System.out);
}catch(IOException e) {
System.out.println("The error is,"+e);
} } }
第 5章 Java例外处理
程序中增加了对例外的处理语句后,就顺利通过
了编译。 catch语句的执行顺序是先捕获最特殊的异常,
之后逐渐一般化,因为,IOException是
FileNotFoundException的父类。
Java允许用户捕获实际需要捕获的异常类的超类,
所以, 一个 catch语句就可以同时捕获多种异常 。 这样,
例 5.3中的 try-catch语句又可以改写为
try {...
}catch(Exception e) {
System.out.pritnln("The error is,"+e.getMessage());}
第 5章 Java例外处理
因为 Exception类是 FileNotFoundException类和
IOException类的超类,所以对一段可能抛出大量不同
类型的异常的程序来说,逐个捕获处理异常可能会较
繁琐,而仅仅捕获它们父类的异常则会较方便。实际
使用中,需要避免捕获最一般的异常类型 (即超类
Exception),因为捕获最一般的异常使得用户往往不能
确切地判断异常的具体类型并作出相应的处理。针对
例 5.3,如果 try-catch语句写为
第 5章 Java例外处理
try {,..
}catch(Exception e) {
System.out.pritnln("The error is,"+e.getMessage());
} catch(IOException e) { System.out.println("The
error is,"+e);
} catch (FileNotFoundException e){
System.out.println("The error is:
"+e.getMessage());
e.printStackTrace(System.out); }
第 5章 Java例外处理
则该异常的后两个 catch捕获语句会始终匹配不到,
造成编译器的混乱 。 所以说, 捕获异常的顺序是和
catch语句顺序相关的, 希望读者注意它的用法 。
与异常处理语句 try-catch相关的另一条语句是
finally语句 。 它为例外处理提供一个统一的出口, 使得
在控制流转到程序的其他部分以前, 能够对程序的状
态作统一的管理, 比如关闭文件或释放其他系统资源 。
实际使用中 finally紧接于 try-catch语句的最后一个 catch
块, 基本语法如下:
第 5章 Java例外处理
try { program where
… errors may arise
} catch (ExceptionClass1 c) {
what to do with it
} catch (ExceptionClass2 d) {
what to do with it
} finally {...}
第 5章 Java例外处理
finally语句的执行是非常决断的, 无条件的执行的 。
无论是否出现异常, 也不管出现哪一种异常或即使 try
语句块中包含有 return,break,continue等语句, 均须
执行 finally语句块所包含的语句 。 这就是说, finally语
句的作用与 C++中类的析构函数相似 。 比如在例 5.3中,
我们打开了文件 file_in,file_out进行读 /写操作, 如果
产生了异常, 就可能需中断, 此时, 对应的文件有可
能无法正常关闭, 这会对文件造成破坏 。 但使用 finally
语句后, 就可把方法中的所有善后工作作统一处理,
既增强程序的可读性, 又避免了对系统或文件的损害 。
所以, 例 5.3可改写为
第 5章 Java例外处理
例 5.4
import java.io.*;
public class ExceptionDemo1 {
public static void main(String args[]) {
int i;
try { FileInputStream fis=new
FileInputStream("file_in.txt");
FileOutputStreamfos=new
FileOutputStream("file_out.txt");
while((i=fis.read())!=-1)
fos.write(i);
第 5章 Java例外处理
fis.close();
fos.close();
}catch (FileNotFoundException e){
System.out.println("The error is:
"+e.getMessage());
e.printStackTrace(System.out);
}catch(IOException e) {
第 5章 Java例外处理
System.out.println("The error is,"+e); }
finally{ if(fis!=null||fos!=null);
System.out.println("Now
closing file…");
fis.close();
fos.close();
} } }
第 5章 Java例外处理
5.2.2 异常的间接声明抛弃
当在程序或代码块中出现异常时, Java语法要求要
么对其捕获, 要么在方法定义中用关键字 throws声明异
常类型并间接将其抛出, 交给其调用者来进行处理 。
也就是说, 异常对象可以从调用栈向后传播, 直到有
合适的方法对其进行捕获为止 。 例如:
public type method Name (args If Any)
throws ExceptionClass1,ExceptionClass2 {

code for method
… }
第 5章 Java例外处理
throws语句中同时可以给出多个异常类, 说明该方
法将不对这些异常进行处理, 而是直接反馈给调用者 。
实际应用中, 抛出的类可以是几个异常的父类 。 比如
在上面代码中, 假设 ExceptionClass1,ExceptionClass2
类的父类为 super_Exception,那么我们可以简单地抛出
类 super_Exception。 例如:
public void Master ()
{try { slaver();
第 5章 Java例外处理
} catch (NumberFormatException e) {
//process here
} catch (ArithmeticException e) {
//process here
} }
public void slaver( ) throws
NumberFormatException,
ArithmeticException
{ // code here}
第 5章 Java例外处理
5.2.3 直接抛出异常
throw语句表示直接抛出一个异常, 后接一个可抛
出的异常类对象 。 指令格式如下:
throw Exception Object;
前面我们讨论的异常均由 Java虚拟机或异常类的实
例生成, 而使用 throw语句可以抛出程序员自行定义的
异常类 。 例如:
class ExceptionDemo2 extends Exception
{..,}
public class Process Exception
第 5章 Java例外处理
{public void Throwmethod()
{if ( // no exception occurred)

else throw new
ExceptionDemo2();
}}
当 throw语句执行时, 它后面的语句将不执行, 此
时程序转而寻找与之匹配的 catch语句, 执行相应的异
常处理程序 。
第 5章 Java例外处理
5.3 异常类的类层次
Java语言采用继承的方式组织各种异常, 所有的
异常类都直接或间接地继承于类 Throwable。 我们可用
图 5.1描述异常的常用类层次 。
从图 5.1中可以看出,Throwable类是所有异常类的
父类。它分为两个子类,Error类和 Exception类。 Error
类包括动态链接失败、虚拟机出错等异常,该类异常
Java不要求捕获,同时系统也不会抛出该类异常。
第 5章 Java例外处理
图 5.1 异常的常用类层次
T h r o w a b l e
E r r o r E x c e p t i o n
L i n k a g e E r r o r V i r t u a l M a c h i n e E r r o r A W T E r r o r A W T E x c e p t i o n I O E x c e p t i o n R u n t i m e E x c e p t i o n
A r i t h m e t i c E x c e p t i o nI n t e r r u p t e d E x c e p t i o nI n d e x O u t O f B o u n d s E x c e p t i o nF i l e N o t F o u n d E x c e p t i o nE O F E x c e p t i o n
第 5章 Java例外处理
类 Exception又可细分为运行异常 (Runtime
Exception)和其他一般异常。与 Error类相似,运行异常
(Runtime Exception)也不需要程序对其进行捕获并处理,
因为它表示 Java虚拟机在运行时所产生的异常。该类
异常的产生非常普遍,如果在每个可能产生这种异常
的地方都加以处理,程序就会变得无法理解,从而影
响程序的可读性和高效性。继承于类 Exception的异常
代表非运行时异常,该类异常必须明确地加以捕获并
处理,否则就无法通过编译。例如,在例 5.3中对 File
Not Found Exception和 IOException两类异常我们都作出
了捕获并处理。
第 5章 Java例外处理
对于运行异常和错误来说, 它们之间的区别主要
在于对系统所造成的危害轻重不同, 恢复正常的难易
程度也不一样 。 错误可以说是一种致命的异常 。 比如
说当遇到诸如 Linkage Error,Vritual Machine Error之类
的错误时, 系统是没有办法恢复的 。 而遇到除数为零
的运行时异常 Arithmetic Exception,我们可以给出捕获
语句加以处理, 不至于导致系统的崩溃 。
第 5章 Java例外处理
最后, 读者需要注意的是对异常的处理往往非常
灵活 。 比如说对运行时异常一般不需要处理, 但是假
如需要输入一个整型数, 而此时用户却输入一个字符
串转换成整型, 且不小心输入了非数字的字符串时,
就会产生运行时异常类 Number Format Exception。 此时,
若按照前面所说不对其加以捕获处理, 系统就会被中
断, 无法进行下去, 因此, 程序中就需加入以下的代
码:
第 5章 Java例外处理

String str=Dialog Box.request("Please input a digit String:
");
Try { int d=Integer.parseInt(str);
}catch (Number Format Exception e) {
System.out.println(" Illegal digit String in "+str); }
下面给出一些常见的错误 (Error)(表 5.1),一般异常
(表 5.2)及运行异常 (Runtime Exception) (表 5.3)的基本格
式及功能 。
第 5章 Java例外处理
表 5.1 Java常见错误列表
类 名 功 能 描 述
ClassCircularityError 初始化某类检测到类的循环调用错误
ClassFormatError 非法类格式错误
IllegalAccessError 非法访问错误
IncompatibleClassChan
gError 非兼容类更新错误
InternalError 系统内部错误
LinkageError 链接错误
NoClassDefFoundError 运行系统找不到被引用类的定义
第 5章 Java例外处理
NoSuchFieldError 找不到指定域错误
NoSuchMethodError 所调用的方法不存在
OutofMemoryError 内存不足错误
UnknownError 系统无法确认的错误
UnsatisfiedLinkError 定义为本地的方法运行时与另外的例程相连接
错误
VerifyError 代码校验错误
VirtualMachineError 虚拟机出错, 可能 JVM错或资源不足
InstantiationError 企图实例化一个接口或抽象类的错误
第 5章 Java例外处理
表 5.2 Java常见的一般异常列表
类 名 功 能 描 述
IllegalAccessException 非法访问异常
ClassNotFoundException 指定类或接口不存在异常
CloneNotSupportException 对象使用 clone方法而不实现 cloneable接口
IOException 输入 /输出异常
InterruptedIOException 中断输入 /输出操作异常
第 5章 Java例外处理
InterruptedException 中断异常 (常常应用于线程操作中 )
EOFException 输入流中遇到非正常的 EOF标志
FileNotFoundException 指定文件找不到
MalformedURLException URL格式不正确
ProtocolException 网络协议异常
SocketException Socket操作异常
UnknownHostException 给定的服务器地址无法解析
UnknownServiceException 网络请求服务出错
UTFDataFormatException UTF格式字符串转换出错
InstantiationException 企图实例化接口或抽象类
NoSuchMethodException 找不到指定的方法
第 5章 Java例外处理
表 5.3 Java常见的运行异常列表
类 名 功 能 描 述
ArithmeticException 算术运算除数为零
IndexOutofBoundException 下标越界错误
ArrayIndexOutofBoundsExceptio
n 数组元素下标越界错误
StringIndexOutofBoundsExcepti
on 字符串下标越界错误
ClassCastException 类型强制转换异常
NegativeArraySizeException 数组的长度为负异常
NullPointerException 非法使用空指针异常
第 5章 Java例外处理
NumberFormatException 非法数据格式异常
IllegalArgumentException 非法参数异常
IllegalMonitorStateException 非法监视器操作异常
IllegalThreadStateException 非法线程状态异常
EmptyStackException 栈空异常, 对空栈进行操作
NoSuchElementException 枚举对象不存在给定的元素异常
SecurityException 安全性异常
第 5章 Java例外处理
当我们在使用异常时,应尽可能使用 Java类库中已
经定义好的类。前面我们讨论过的 throw语句可以抛出
用户自定义的异常类,其实,Java类库中提供了大多
数常用的类库,往往只是在很少的情况下才需要用户
自己定义异常类。用户自定义的异常类必须是
Throwable的直接或间接的子类。总之,当我们使用异
常的时候,可以参考以下几点建议:
第 5章 Java例外处理
(1) 对运行时异常类的处理, 由于其发生的多样性,
程序中可不对它进行处理, 而直接交给系统去处理 。
(2) 如果我们确定异常在程序中产生的地点或时间,
则需像对一般异常处理的方式一样对其捕获并处理 。
(3) 当 Java所给定的异常类不能满足我们要求时, 需
要自定义异常类 。 如果该异常符合条件 1,则应定义为
运行时异常;如果符合条件 2,则应定义为一般异常类 。
第 5章 Java例外处理
下面我们给出一个完整的例子。该例是模拟整型除
法运算,但使用了 Java的图形用户界面,读者可以不
管程序的其他用法,着重关注程序中对异常的处理方
法。类 Division Frame中的方法 perform Division进行除
法的运算,其中可能产生两种异常,Number Format
Exception和 Arithmetic Exception,但在该方法中并没有
对它们进行捕获,只是通过 throws语句将它们简单抛出,
最后由调用者来进行捕获并处理。
第 5章 Java例外处理
例 5.5
public class Main {
public static void main (String [] args) {
Division Frame divWin = new Division Frame();
div Win.setVisible(true); }}
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
第 5章 Java例外处理
public class DivisionFrame extends ExitFrame {
// instance variables
private JTextField numerator,denominator,result;
private String task = "Enter integers and press '=' to
perform division.";
private JLabel taskMsg = new JLabel(task,
JLabel.CENTER);
private String welcome = "Welcome to the deluxe integer-
division calculator";
private JLabel statusMsg = new JLabel(welcome,
JLabel.CENTER);
第 5章 Java例外处理
// constructor
public DivisionFrame ( ) {
setTitle("Performing Integer Division");
setBounds(50,100,750,200);
Font f = new Font("SansSerif",Font.BOLD,30);
taskMsg.setFont(f);
taskMsg.setForeground(Color.blue);
statusMsg.setFont(f);
statusMsg.setForeground(Color.blue);
numerator = new JTextField("0",7);
第 5章 Java例外处理
numerator.setFont(f);
denominator = new JTextField("1",7);
denominator.setFont(f);
result = new JTextField("0",7);
result.setFont(f);
JLabel divSign = new JLabel("/",JLabel.CENTER);
divSign.setFont(new Font ("SansSerif",Font.BOLD,
50));
divSign.setForeground(Color.black);
JButton equalBut = new JButton("=");
equalBut.setFont(f);
equalBut.addActionListener(new ActionListener() {
第 5章 Java例外处理
public void actionPerformed(ActionEvent evt) {
try { performDivision();
} catch (NumberFormatException e) {
statusMsg.setForeground(Color.red);
statusMsg.setText("numbers must both
be integers,try again");
taskMsg.setText(" ");
} catch (ArithmeticException e) {
statusMsg.setForeground(Color.red);
statusMsg.setText("cannot divide by zero:
try again");
taskMsg.setText(" ");
}}
第 5章 Java例外处理
});
JPanel p1 = new JPanel();
p1.add(numerator); p1.add(divSign);
p1.add(denominator);
p1.add(equalBut); p1.add(result);
JPanel p2 = new JPanel();
p2.add(taskMsg);
JPanel p3 = new JPanel();
p3.add(statusMsg);
Container c = getContentPane();
c.add(p1,"Center"); c.add(p2,"South"); c.add(p3,
"North"); }
第 5章 Java例外处理
public void performDivision ()throws
NumberFormatException,
ArithmeticException {
int numValue = Integer.parseInt(numerator.getText());
int denomValue =
Integer.parseInt(denominator.getText());
int divValue = numValue/denomValue;
result.setText(""+divValue);
statusMsg.setForeground(Color.blue);
statusMsg.setText("division performed without error");
taskMsg.setText(task); }}
第 5章 Java例外处理
当我们输入正确的数据时, 程序的运行结果如图
5.2所示;如果我们输入的第二个参数为 0,则结果如图
5.3所示;如果接下来输入非数字的字符, 则结果如图
5.4所示 。
第 5章 Java例外处理
图 5.2
第 5章 Java例外处理
图 5.3
第 5章 Java例外处理
图 5.4