UML软件工程组织

JAVA基础:面向对象的例外处理
作者: 不详  来源:赛迪网论坛

什么是例外 、例外处理

例外就是在正常情况以外的事件。Java之中的例外是指程序运行中发生的异常事件,这些异常件将阻止程序的正常运行。比如出现了数组越界、用户输入错误等等。而顾名思义,例外处理就是对这些例外进行处理。

 所有的高级计算机编程语言里都有判断是否出现了例外的语句,每个好的计算机程序都会有对例外进行处理的程序段。只不过在不同的计算机编程语言里面,对例外的称呼不同,例如有的语言里所讲的错误处理,其实就等同于Java里面的例外处理。这就像诸葛亮先生有两个名字,孔明是他诸葛亮也是他,还有人称呼他为诸葛先生… …,只是称呼不同罢了,意义是一样的。

 抛弃之

在许多高级语言中都是通过使用if语句来判断是否出现了例外,并进行处理的。Java作为一个完全基于面向对象的语言,例外处理也是采用面向对象的方法。在一个方法的运行过程中如果发生了例外,则这个方法将生成一个代表该例外的对象,并把它提交给正在运行这个方法的系 统。我们把这个过程称为抛弃一例外。

 就像抛弃这个球一样,把它给抛掉了。抛弃一个例外的过程就和我们平时工作中碰到了特殊情况无法解决,需要写一份报告交把这个棘手的 问题上报上级主管部门一样。

捕获之

 系统在运行的时候查找处理提交给它的例外的方法,这个过程称为捕获一个例外。这就和法官判案时查找相应的法律条文的过程是一样的。

优越性

1.利用以上这些方法处理例外,使得例外处理的程序代码与普通的程序代码不再混为一体,减少了编程序的工作量,同时也增加了程序可读性 。

2.利用面向对象的方法来处理例外,可以对各种不同的例外事件进行分类,然后再处理之,从而具有了良好的接口和层次性。

3.利用类的层次性既可以区分不同的例外分别处理,也可以把具有相同父类的多个例外统一处理,具有相当的灵活性。

由以上几点可知,Java的这种面向对象的例外处理机制为那些具有动态运行特性的复杂程序提供了强有力的控制方式。

以上这些优越性背下来就可以了,到时候可以用来在孩儿们面前炫耀一下自己的知识渊博。

与例外处理相关的类

 用面向对象的方法来进行例外处理首先必须建立类的层次。如图20.1所示,类Throwable是最顶层的,只有它的子类才可以作为一个例外被 抛弃。

运行时与非运行时例外

Java有运行时例外和非运行时例外之分。

所谓运行时例外就是由系统在Java程序运行的过程中检测到的例外,例如除零溢出(除数为零导致的错误)、数组越界等。由于它们可能在程序的任何位置发生,而且谁也无法在程序运行以前计算出它们会发生多少次,所以Java语言编译器允许Java程序不对它进行处理。

除此之外的其他例外则被称为非运行时例外。



  图 20.1 例 外 处 理 — — 类 的 层 次

用户自己定义的例外都是非运行时例外。然而并非所有非运行时例外都是用户自己定义的例外。

所谓用户自己定义的例外,就是你在编写程序的时候在你的程序里面定义的那些例外,以便使得你的程序具有更高的可靠性,不会轻易地出 差错。

Java编译器要求必须捕获或声明所有的非运行时例外。对于用户自定义例外,这是十分显然的;否则,系统就不知道这些用户自定义的例外的特性。知己知彼才能百战百胜。

简单的例外处理
 
 运行时例外的处理

先看看下面这两个例子。

程序20.1

public class REP{

  public static void main(String args[ ]) {

    int AE = 1/0; // AE 等 于 1 除 以 0 , 将 导 致除 0
溢 出 例 外

    }

  }

程序 20.2

public class REP{

  public static void main(String args[ ]) {

    int i = 0;

    int AE = 1/i; // AE 等 于 1 除 以 i , 而 i 等于 0
, 也 将 导 致 除 0 溢 出

    }

  }

在程序20.1和程序20.2中都出现了除数为0导致的“除0溢出”例外,这属于运行时例外。此时,运行程序的系统会自动把生成的例外对象交给缺省的(也就是默认的)例外处理程序,在计算机屏幕上显示出这个例外的内容及发生此例外的位置。在JDK环境下运行这两个例子程序。( 有关JDK开发环境的介绍请参见《开发环境》一章)

 程 序 20.1 的 运 行 结 果 为 :

    c:\java\exam >javac REP.java

    REP.java:3: Arithmetic exception.

        int AE = 1/0;

            ^

    1 error

可见,程序在编译的时候编译器就指出了错误。此程序不能通过编译。无法生成可以运行的文件。

程 序 20.2 的 运 行 结 果 是 :

    c:\java\exam>javac REP.java

    c:\java\exam>java REP

    java.lang.ArithmeticException: / by zero

        at REP.main(REP.java:4)

程序20.2虽然通过了编译,编译器没有指出有错误,从而生成了可以运行的程序文件,但是该程序在运行时系统指出出现了例外。

非运行时例外

我们也是先看一个例子:

程序20.3

class MyE extends Exception{ // 定 义 一 个 例 外 类
MyE

    private int detailA,detailB;

    MyE(int a,int b){

        detailA = a;

        detailB = b;

        }

    public String toString(){

        return "MyException : "+detailA+"<"+detailB;

        }

    }


public class ED{ // 定 义 一 个 类 ED

static void compare(int a,int b) throws MyE {

    System.out.println("***************************");

    System.out.println("call compare("+a+","+b+")");

    if (a

        throw new MyE(a,b);

    System.out.println("normal exit : "+a+">
= "+b);

    }


static void callcompare(int a,int b){

    try{

        compare(a,b);

      } catch(MyE e){

            System.out.println("Catch "+e);

                }

        finally{

            System.out.println("return from
callcompare()");

            }

    }


public static void main (String args[ ]){

        callcompare(10,5);

        callcompare(5,5);

        callcompare(5,10);

        }

}

程序20.3抛弃了自己的例外。上例对两个整数a和b进行了比较(compare),当a(=b时程序正常运行,当a((b时程序抛弃例外MyException 。

在JDK里例20.3的运行结果如下:

c:\java\exam>java ED


    ***************************

    call compare(10,5)

    normal exit : 10> = 5

    return from callcompare()

    ***************************

    call compare(5,5)

    normal exit : 5> = 5

    return from callcompare()

    ***************************

    call compare(5,10)

    Catch MyException : 5<10

    return from callcompare()

例外的抛弃、捕获和声明

除对运行时例外可以不做处理外,例外处理还有以下几种方法:

使用throws子句生命例外;

定义自己的例外类,并用throw语句来抛弃它;

使用try-catch-finally语句捕获例外。

抛弃例外

在Java语言中捕获一个例外之前,必须有一段Java代码生成一个例外对象并把它抛弃。抛弃例外的代码可以是你自己Java的程序,JDK中的某 个类,或者是Java运行时系统。这就像在蓝球场上打球一样,你若想接到一个球,就必须有人先抛出这个球,不管这人是中锋,还是后卫,亦或是对方球员。同理,如同所有人抛球都必须用手一样,无论是你自己的程序还是运行时系统,都必须使用throw语句来抛弃例外。

例如,在例20.3的compare方法中就使用throw语句来抛弃一个例外:

throw new MyE(a,b);其中MyE是Exception的一个子类。

class MyE extends Exception{ // class MyException }

由throw抛弃的例外必须是Throwable类或其子类的对象。

声明例外

在很多情况下,生成例外的方法并不需要处理它,而是用throws子句来声明它,以向上传递。如例20.3中

static void compare(int a,int b) throws MyE
{

这样就在compare方法中声明了例外MyE 。

一个方法中也可以同时声明多个例外,只需throws在后列出所有要声明的例外即可。例如


    static void Proc ( ) throws MyE , ArithmeticException{

    … …

    }

捕获例外

捕获例外需使用try-catch-finally语句。

 在例20.3的callcompare方法中,try语句在{}中指定了一段代码,该代码可能会抛弃几个例外;其后的catch用于处理这些例外;finally则提 供了统一的出口。

static void callcompare(int a,int b){

    try{

        compare(a,b);

    }

        catch(MyE e){

            System.out.println("Catch "+e);

            }

        finally{

            System.out.println("return from
callcompare()");

            }

    }

程序20.4importjava.awt.*;

import java.applet.*;

class MyE extends Exception{ // class MyException

    private int detailA,detailB;

    MyE(int a,int b){

        detailA = a;

        detailB = b;

            }

    public String toString(){

        return "MyException : "+detailA+"<"+detailB;

            }
}

 

class Cons{ //设置一个常数,让它代表两条线之间的距离final int jmp = 13;

    }

public class ED extends Applet{ // class Exception
Demo

    static void compare(int a,int b,Graphics g,int
Ln,int col) throws MyE {

      Cons jump = new Cons();

      g.drawString("***************************",col,Ln);

      g.drawString("call compare("+a+","+b+")",col,Ln+jump.jmp);

      if (a

        throw new MyE(a,b);

      g.drawString("normal exit :"+a+">
= "+b,col,Ln+2*jump.jmp);

        }


static void callcompare(int a,int b,Graphics
g,int Ln,int col){

  Cons jump = new Cons();

    try{

        compare(a,b,g,Ln,col);

      }

        catch(MyE e){

        g.drawString("Catch "+e,col,Ln+2*jump.jmp);

            }

      finally{

            g.drawString("return from callcompare()",col,Ln+3*jump.jmp);

            }

    }


public void paint (Graphics g){

    Cons jump = new Cons();

    int Ln;

    int col;

    Ln = 10; col = 20;

    callcompare(10,5,g,Ln,col);

    Ln = Ln+5*jump.jmp;

    callcompare(5,5,g,Ln,col);

    Ln = Ln+5*jump.jmp;

    callcompare(5,10,g,Ln,col);

      }

    }

程序20.4是程序20.3的Applet形式,它的运行结果如图20.2所示。


       图 20.2 程 序 20.4 的 执 行 结 果

几件值得注意的事情

自定义的例外类的类名通常可以以Exception结尾。例如:MyException , MyArithmeticException 等 。

对于运行时例外可以不捕获、声明,而提交运行时系统处理。

在捕获或声明例外时,要选取合适类型与层次的例外 。

处理例外既可以在方法内捕获并处理,也可以提交上层方法处理。

使用finally语句可为例外处理提供统一的出口,通常可在finally语句中进行资源清除工作,如关闭已打开的文件等。

小结

Java采用面向对象的例外处理机制减小了编程量,增加了灵活性,增强了程序的可读性和可靠性,有利于编写具有动态运行特性的复杂程序。

对非运行时例外必须捕获或声明。

对于自定义的例外类,通常作为类Exception的子类,而不作为类Error的子类。因为类Error通常用于系统内严重的硬件错误。

抛弃的例外必须是Throwable类或其子类的对象。

注意区分throw和throws的用法:

throw用于抛弃例外;

throws用于声明例外。

 

版权所有:UML软件工程组织