Java-错误处理机制学习(一)异常处理

注意:本文介绍Java中的异常处理理论知识及相关语法结构,对于实际应用来说是万万不够的。关于如何高效地使用异常,请查看Java-高效地使用Exception-实践

 

异常处理的思想是,当应用程序处于异常时,它可以声明这种异常;然后这种异常将被捕获到并得到妥善地处理,从而避免出现严重后果。所谓异常,是值与程序的正常运行逻辑相违背的非正常事件,比如,读取文件内容时,文件不存在;或者说对数组进行操作时,数组下标越界等等。而用户登录时口令验证失败这种情况不能算作异常,因为它是验证程程序正常运行逻辑的一部分。

一、异常层次结构与分类

Java中的异常层次结构如下图所示:

 

Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误。对于这种错误应用程序是无能为力的,因此应用程序不应该抛出这种类型的对象。

Exception层次结构分解为两个分支:一支派生于RuntimeException,它表示由程序错误导致的异常。比如空指针、数组越界、错误的类型转换等等。

另一个分支表示程序本身没有问题,出问题的是IO读写等外部操作,比如在文件尾部读取数据、打开了错误的URL等等。

Java语言规范将派生干Error类或RuntimeException类的所有异常称为未检查(unchecked) 异常,所有其他的异常称为已检查(checked)异常。编译器将核査是否为所有的已检査异常提供了异常处理器。

二、声明已检查异常

根据异常规范,方法应该在首部声明所有可能抛出的异常。然而未检査异常要么不可控制(Error), 要么就应该避免发生(RuntimeException)。因此,规定方法必须对所有可能抛出的已检查异常进行声明,否则无法通过编译。

那么,我们如何知道一个方法究竟存在哪些已检查异常呢?不用担心,编译器能够对我们进行提示。当方法调用了可能抛出异常的方法时,eclipse将自动告警,如下图:

 

如果不按照提示进行修改则程序无法通过编译。

三、抛出异常

假设应用程序现在遇到了一个错误,需要抛出异常进行告警。那么,首先要确定异常的类型。Java已经事先定义好了许多Exception,常见的有IOException/SQLException等等,更多类型可以通过查阅API来确定。当然,我们也可以继承Exception然后创建自己的异常。接下来,创建异常实例,并使用throw关键字抛出异常。最后,在方法签名中声明抛出的异常类型。示例代码如下:

public void read(File file) throws Exception{
        if(!file.exists()){
            Exception e = new FileNotFoundException();
            throw e;
        }
    }

四、捕获异常

异常的捕获、处理格式为:

public void callRead(){
        try {
            //可能抛出异常的代码
            read(new File("filename1"));
            read(new File("filename2"));
        } catch (Exception e) {
            //异常处理代码
            e.printStackTrace();
        }
        finally{
            //无论如何需要执行的代码,比如释放资源    
        }
    }

 

其中,try{}catch{}是必须的,finally是可选的。可能抛出异常的代码必须放在try{}中,否则异常无法被捕获;当捕获异常时,直接跳转到catch{}进行异常处理。比如说,读取filename1时捕获了异常,那么read(new File("filename2"));这局代码将被跳过不再执行。

通常可能发生的异常不止一种,不建议都使用Exception对象进行捕获,因为它太通用,不能反映异常的具体类型。正确的做法是对不同的异常分别处理,即叠加多个catch块。

程序中总有一些工作比如释放资源,无论发生异常与否都需要去做,那么可以放在finally{}中,它在catch{}完成后一定会执行。即使前面有return语句,也将在finally{}结束后才返回。

五、再次抛出异常与异常链

考虑这种情景:应用程序调用了server模块。模块内部可能会抛出加载资源出错、访问数据库出错等多种异常。对于应用程序来说,它只关心server模块是否发生异常,而不关系异常的细节。然而异常细节又不能丢失,它应该保存并由相应的人员去识别和处理。因此,捕获到底层异常时,我们需要根据它构造出一个更高级的异常并抛出,示例代码如下:

public void convertExceptionTypeDemo() throws ServerException{
        try {
            //access the database
        } catch (SQLException e) {
            //异常处理代码
            throw new ServerException("database error" + e.getMessage());
        }
    }

然而,Java中有更好的处理方法,就是将原始异常设置为新异常的诱饵,示例如下:

public void chainedExceptionDemo() throws Throwable{
        try {
            //access the database
        } catch (SQLException e) {
            //异常处理代码
            Throwable serverException = new ServerException("database error");
            serverException.initCause(e);
            throw serverException;
        }
    }

捕获到异常时,使用下列语句就能提出原始异常:

Throwable exception = serverException.getCause();
posted on 2015-08-13 17:06  pzy4447  阅读(581)  评论(0编辑  收藏  举报