Java语言中的异常处理

java异常分类

异常类层次

alt none

Throwable

Java中所以的异常都是有Throwable继承而来。

Error

Error类层次结构描述了JAVA运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种类型的错误对象。如果程序出现了这样的内部错误,除了通告给用户,并尽力使程序安全终止之外,再无能为力。这种情况很少出现。

Exception

在设计JAVA程序时,需要关注Exception层次结构。这个层次结构又分为两个分支:

Runtime Exception

由程序错误导致的异常属于Runtime Exception,相当于C++中的logic_error类。如果出现“Runtime Exception”异常,那么就一定是你的问题。应该通过检测数组下表是否越界来避免ArrayIndexOutOfBoundsException异常;应该通过在使用变量之前检测是否为空来杜绝NullPointerException异常的发生。派生于Runtime Exception的异常包含下面几种情况:

IOException

派生于IOException的异常包含下面几种情况:

未检查异常和已检查异常

未检查异常

Java语言规范将派生于Error类或RuntimeException类的所以异常称为“未检查异常(unchecked exception)”。

已检查异常

除上面所述的未检查异常外的所以异常都称为“已检查异常(checked exception)”。编译器将核查是否为所有的已检查异常提供了异常处理器。

声明异常

方法应该在其首部使用throws关键字声明所有可能抛出的异常。例如:

public FileInputStream(String name) throws FileNotFoundException

当一个方法有可能抛出多个已检查异常时,那么必须在方法的首部列出所有的异常类。例如:

class MyClass {
    public void MyMethod(String s) throws EOFException, IOException {
        //... ...
    }
}

在自己编写的方法时,不必将所有可能抛出的异常都进行声明。至于什么时候需要在方法中用throws字句声明异常,什么异常必须使用throws字句声明,需要记住在遇到下面4种情况时应该抛出异常:

如果出现前两种情况之一,则必须告诉调用这个方法的程序员有可能抛出异常。但是,并不需要声明Java的内部错误,即那些从Error继承而来的错误。任何程序代码都具有抛出那些异常的潜能,而我们对其没有任何的控制能力。同样的,也不应该声明从RuntimeException继承的那些未检查异常。例如:

    class MyClass {
       public  void MyMethod(String s) throws ArrayIndexOutOfBoundsException //这里不必要做声明未检查异常 
    }

总之一个方法必须声明所有可能抛出的已检查异常,而未检查异常要么不可控制(Error),要么就应该避免(RuntingException)。如果方法没有声明所有可能发生的已检查异常,编译器就会给出一个错误信息。

子类中的异常

如果在子类中覆盖了超类的一个方法,子类方法中声明的异检查异常不能超过超类方法中声明的异常范围(也就是说,子类中抛出的异常范围更加小,或者根本不抛出异常)。

抛出异常

抛出一个已经存在的异常类,一般步骤如下:

例如:

void  MyMethod(Scanner in) throws EOFException {
    while(...) {
        if(!in.hasNext) {//EOF encountered
            if(n < len) 
                throw new EOFException();
        }
    }
}

创建异常

在程序中,可能会遇到任何标准异常类都没有能够充分描述清楚的问题。在这种情况下,我们可以定义一个派生于Exception或其子类的类,例如:

class FileFormatException extends IOException {
    public MyException() {}
    public MyException(String str) {
        super(str);
    }
}

使用MyException:

string readData(BufferedReader in) throws FileFormatException {
    ...
    while(...) {
        if(ch == -1){ //EOF encourntered
            if(n < len)
                throw new FileFormatException();
        }
    }
    return s;
}

捕获异常

Java中捕获异常的方法跟C++中一样,可以使用try catch字句。

捕获单个异常

public void read(String filename) {
    try{
        InputStream in = new InputStream(filename);
        int b;
        while((b = in.read()) != -1) {
            ...
        }
    } catch(IOException e) {
         e.printStackTrace();
    } finally {
        in.close();
    }
}

捕获多个异常

在一个try语句块中可以捕获多个异常类型,并对不同类型异常做不同的处理,例如:

try {
    //可能抛出异常的代码
} catch(MalformatURLException e1) {
    //处理MalformatURLException
} catch(UnknownHostException e2) {
    //处理UnknowHostException
} catch(IOException e3) {
    //处理IOException
} finally {
   //一些抛出异常后的处理
}

与C++语言的比较

ref:《Java 核心技术》