第五章 异常处理
Java 程序设计
教学 内容
? 异常的概念
? 异常的分类
? 捕获异常
? 声明异常
? 抛出异常
? 创建自己的异常
? 总 结
5.1异常的概念
? 例外就是在程序的运行过程中所发生的异常
事件,它中断指令的正常执行。 Java中提供
了一种独特的处理例外的机制,通过例外来
处理程序设计中出现的错误。
? 见 demo\mod02\NoException.java
? 见 demo\mod02\ExceptionDemo1.java
? demo\mod02\ExceptionDemo2.java
异常的处理机制
? ◇ 捕获例外:
当 Java运行时系统得到一个例外对象时,它将会沿着
方法的调用栈逐层回溯,寻找处理这一例外的代码。找到
能够处理这种类型的例外的方法后,运行时系统把当前例
外对象交给这个方法进行处理,这一过程称为捕获 (catch)
例外。这是积极的例外处理机制。如果 Java运行时系统找
不到可以捕获例外的方法,则运行时系统将终止,相应的
Java程序也将退出。
◇ 声明抛弃例外:
如果一个方法并不知道如何处理所出现的例外,则可
在方法声明时,声明抛弃( throws)例外。这是一种消极
的例外处理机制。
异常类层次
? 在 jdk中,每个包中都定义了例外类,而所有的例外类都直接或间
接地继承于 Throwable类。下图为 jdk中例外类的继承关系。
异常的两大类
? Error
动态链接失败,虚拟机错误等,通常 Java程序不应该捕
获这类例外,也不会抛弃这种例外。
Exception
1)运行时例外:
继承于 RuntimeException的类都属于运行时例外,例如
算术例外(除零错)、数组下标越界例外等等。由于这些
例外产生的位置是未知的,Java 编译器允许程序员在程序
中不对它们做出处理。
2)非运行时例外:
除了运行时例外之外的其他由 Exception 继承来的例外
类都是非运行时的例外,例如 FileNotFoundException(文
件未找到例外)。 Java编译器要求在程序中必须处理这种
例外,捕获例外或者声明抛弃例外。
? throw:用户自己产生异常
异常的处理
? java语言中有两种例外处理机制:捕获例外和声明抛弃例外
? 捕获异常
捕获例外是通过
try-catch-finally
语句实现的。
try{
.,//常规的代码,...
}catch( ExceptionName1
e ){
//处理异常,.....
}catch( ExceptionName2
e ){
......
}
......
}finally{
//不论发生什么异常
(或者不发生任何异常 ),都要执
行的部分
}
try
? 捕获例外的第一步是用 try{…} 选定捕获例外的范围,由
try所限定的代码块中的语句在执行过程中可能会生成例外
对象并抛弃。
? 在 try{…} 这一部分,存放 常规的代码,期望或可能出错的代
码段
catch
? 每个 try代码块可以伴随一个或
多个 catch语句,用于处理 try代
码块中所生成的例外事件。
catch语句只需要一个形式参数
指明它所能够捕获的例外类型,
这个类必须是 Throwable的子
类,运行时系统通过参数值把被
抛弃的例外对象传递给 catch块。
? 在 catch块中是对例外对
象进行处理的代码,与
访问其它对象一样,可
以访问一个例外对象的
变量或调用它的方法。
getMessage( )是类
Throwable所提供的方法,
用来得到有关异常事件
的信息,类 Throwable还
提供了方法
printStackTrace( )用来
跟踪异常事件发生时执
行堆栈的内容
catch
try{,.....}
catch( FileNotFoundException e )
{
System.out.println( e );
System.out.println( "messag
e,"+e.getMessage() );
e.printStackTrace( System.o
ut ); }
catch( IOException e )
{
System.out.println( e );}
? catch 语句的顺序:
捕获例外的顺序和
catch语句的顺序有关,
当捕获到一个例外时,
剩下的 catch语句就不再
进行匹配。因此,在安
排 catch语句的顺序时,
首先应该捕获最特殊的
例外,然后再逐渐一般
化。也就是一般先安排
子类,再安排父类。
finally
? 捕获例外的最后一步是通过 finally语句为例外处理提供一
个统一的出口,使得在控制流转到程序的其它部分以前,
能够对程序的状态作统一的管理。不论在 try代码块中是否
发生了异常事件,finally块中的语句都会被执行。
finally
? finally在文件处理时非常有用
? try {
? 对文件进行处理的程序 ;
? }catch(IOException e) {
? //对文件异常进行处理 ;
? }finally {
? 不论是否发生异常,都关闭文件 ;
? }
捕获异常
? 编写 Java程序,包含三种异常
? 算术异常,字符串越界,数组越界
? 观察输出信息,
? 每个异常对象可以直接给出信息
声明抛出异常
? 1.声明抛出异常 如果在一个方法中生成了一个例外,但是
这一方法并不确切地知道该如何对这一异常事件进行处理,这
时,一个方法就应该声明抛弃例外,使得例外对象可以从调用
栈向后传播,直到有合适的方法捕获它为止。
声明抛弃例外是在一个方法声明中的 throws子句中指明的。例如:
public int read () throws IOException{
......}
throws子句中同时可以指明多个例外,之间由逗号隔开。例如:
public static void main(String args[]) throws
IOException,IndexOutOfBoundsException {…}
Mod02\Exception1.java观察运行结果
声明抛出异常
? 2.抛出例外
抛出例外就是产生例外对象的过程,首先要生成例外
对象,例外或者由虚拟机生成,或者由某些类的实例生成,
也可以在程序中生成。在方法中,抛出例外对象是通过
throw语句实现的。
例如:
IOException e=new IOException();
throw e ;
可以抛出的例外必须是 Throwable或其子类的实例。
下面的语句在编译时将会产生语法错误:
throw new String("want to throw");
抛出异常
.抛弃异常,不是出错产生,而是人为地抛出
? throw ThrowableObject;
? throw new ArithmeticException();
? 例,编写程序人为抛出 (JavaThrow.prj)
ArithmeticException,
ArrayIndexOutOfBoundsException
StringIndexOutOfBoundsException
Mod02\JavaThrow.java
A method Exception Another method
throw caught
注意
? 自定义例外类必须是 Throwable的直接或间接子类。
注意:一个方法所声明抛弃的例外是作为这个方法与
外界交互的一部分而存在的。所以,方法的调用者必须了
解这些例外,并确定如何正确的处理他们。
创建自己的异常
? 不是由 Java系统监测到的异常 (下标越界,被 0-除
等 ),而是由用户自己定义的异常,
? 用户定义的异常同样要用 try--catch捕获,但必须
由用户自己抛出 throw new MyException.
? 异常是一个类,用户定义的异常必须继承自
Throwable或 Exception类,建议用 Exception类,
创造自己的异常
? 形如,
? class MyException extends Exception
? {….};
? 例 1,计算两个数之和,当任意一个数超出范围时,抛出自己的异常
public class NumberRangeException extends
Exception
{ public NumberRangeException(String msg)
{ super(msg); }
}
创建自己的异常
public boolean action(Event evt,Object arg)
{ try {
int answer = CalcAnswer();
answerStr = String.valueOf(answer);
}catch (NumberRangeException e)
{ answerStr = e.getMessage(); }
repaint();
return true;
}
4.6 创造自己的异常
?,
public int CalcAnswer() throws NumberRangeException
{ int int1,int2; int answer = -1;
String str1 = textField1.getText();
String str2 = textField2.getText();
try { int1 = Integer.parseInt(str1);
int2 = Integer.parseInt(str2);
if ((int1 < 10) || (int1 > 20) ||
(int2 < 10) || (int2 > 20))
{ NumberRangeException e =
new NumberRangeException
(”Numbers not within the specified range.");
throw e;
}
answer = int1 + int2;
}catch (NumberFormatException e)
{ answerStr = e.toString(); }
return answer;
}
创建自己的异常
例 2,在定义银行类时,若取钱数大于余额则作为异常处理
(InsufficientFundsException).
思路,产生异常的条件是余额少于取额,因此是否抛出异常
要判断条件
取钱是 withdrawal方法中定义的动作,因此在该方法中产
生异常,
处理异常安排在调用 withdrawal的时候,因此 withdrawal方
法要声明异常,由上级方法调用
要定义好自己的异常类
见 mod08\exceptondemo.java
创造自己的异常
?,class Bank{ double balance;
public void deposite(double dAmount)
{ if(dAmount>0.0) {balance+=dAmount;}}
public void withdrawal(double dAmount)
throws InsufficientFundsException
{ if (balance<dAmout) {
throw new InsufficientFundsException(this,dAmount);
}
balance=balance-dAmount;
}
public void show_balance()
{ System.out.println("The balance is "+(int)balance);}
}
创建自己的异常
public class ExceptionDemo
{ public static void main(String args[])
{ try
{ Bank ba=new Bank(50);
ba.withdrawal(100);
System.out.println(“Withdrawal successful!”);
}catch(Exception e)
{ System.out.println(e.toString()); }
}
创建自己的异常
public class InsufficientFundsException extends Exception
{ private Bank excepbank;
private double excepAmount;
InsufficientFundsException(Bank ba,double dAmount)
{ excepbank=ba;
excepAmount=dAmount;
}
public String excepMesagge()
{ String str=“The balance”+ excepbank.showBalance()+
“The withdrawal was”+excepAmount;
return str; }
小结
1.一般格式,正常程序和出错处理分离开来
try { Java statement;
}catche(ExceptionType1 ExceptionObject) {
Exception1 handling;
} catche(ExceptionType2 ExceptionObject) {
Exception2 handling;
}….
}finally {
final handling;
// (统一的出口,最终必定要执行 )
}}
小结
? 2.把异常传播给堆栈,沿着被调用的顺序往前寻找,只要找到符合该异常
种类彻底异常处理程序,就交给这部分程序去处理
Method1 Method2 Method3 Read-filecall call call
Try catch
产生异常
throwsthrowsthrows
小结
3.异常可以人为地抛出,用 throw new 语句
4.异常可以是系统已经定义好的,也可以是用户自
己定义的
5.用户自己定义的异常一定继承自 Throwable或
Exception类
作业
? 当用户按,T”或,t”时,人为抛出一个算术异常,处
理 方式为打印出错信息
import java.awt.*; import java.applet.*;
public class keyException extends Applet
{ final int LOWERCASE_T = 116;
final int UPPERCASE_T = 84;
String str; int count=0;
public void paint(Graphics g)
{ g.drawString(" "+str+count,5,20); }
public boolean keyDown(Event evt,int key)
{if ((key == LOWERCASE_T) || (key == UPPERCASE_T))
{ try{ throw new ArithmeticException();}
catch(ArithmeticException e)
{ count++; str=e.toString(); repaint();}
return true; } return false; }