5.5 异常处理

开发过程中,代码的执行情况往往无法完全控制,例如,磁盘文件的读写权限、网络的连接状态、远程资源的状态(如远程数据库)等。如果不能有效处理代码执行时的问题,程序就会崩溃,给用户带来非常不好的体验。

作为开发人员,能够处理程序运行中出现的问题是一项非常重要的工作。Java中也提供了这样的机制。下面就讨论异常处理的相关内容。

5.5.1 异常类

首先,在Java程序中出现异常时,相关信息会保存到Exception类或其子类的对象中,可以使用异常对象的成员来获取异常信息,如:

□ getMessage()方法,返回异常的详细信息。

□ getLocalizedMessage()方法,返回本地化的异常信息。

□ printStackTrace()方法,显示调试信息。

下面的代码会模拟除以零错误,并显示捕获的异常信息。

代码执行结果如图5-7所示。

图5-7 除以零产生的异常

5.5.2 try-catch-finally语句

前面的示例中已经使用了try语句结构,其完整的应用格式如下。

    try{
        // 可能出现异常的代码
    }catch(Exception ex){
        // 处理捕获的异常
    }finally{
        // 最终处理工作
    }

这个语句结构的组成部分包括以下几个。

□ try语句块中包含应用的主要代码,但这些代码可能会出现异常。

□ catch语句块可以有多个,每一个都可以处理具体的异常类。此外,一个catch语句块也可以处理多个异常,此时可以使用|符号分隔圆括号中的异常对象。

□ finally语句块为可选,如果使用finally语句块,则无论try语句块中的代码是否出现异常,都会执行finally语句块中的代码,所以可以在这里做一些清理工作或者数据的最终处理。

下面的代码同样模拟一个除以零的异常,这一次添加了finally语句块。

代码执行结果如图5-8所示。

图5-8 使用try-catch-finally语句结构

5.5.3 throw语句

throw语句用于抛出异常,例如,当程序中继续执行代码的条件不满足时,就可以抛出异常,并由catch语句块捕获。下面的代码在try语句块中使用throw语句抛出一个异常。

图5-9 使用throw语句

代码执行结果如图5-9所示。

5.5.4 throws关键字

throws关键字一般用于方法的定义,说明方法可能会抛出的异常类型,调用方法时,应该针对相应的异常类型进行处理。下面的代码演示了throws关键字的使用方法。

代码很简单,其中包括JavaDemo类(JavaDemo.java文件)中的三个静态成员。

首先,定义一个静态的嵌入类TestException,它继承自Exception类,其中,重写了getMessage()方法,用于返回异常的描述信息。

然后,定义一个静态方法m1(),这里使用throws关键字说明m1()方法可能会产生TestException异常。m1()方法中,除了抛出TestException异常之外,其他什么操作也不会执行。然而,m1()方法的调用者未必知道方法实现的真相。

NetBeans开发环境中,在代码中直接调用m1()方法时,会看到因为使用了throws关键字而给出的提示,如图5-10所示。

图5-10 未处理异常的提示

代码中,调用使用了throws关键字的方法时,就应该使用try-catch语句结构来处理可能的异常,如下面的代码所示。

图5-11 异常测试

执行代码,可以看到程序很“优雅”地捕获了异常,如图5-11所示。

5.5.5 try()语句结构

try()语句结构是Java 7中的新成员,它可以自动释放对象。不过,对象的类型必须实现AutoCloseable接口。

下面的代码(CAutoCloseable.java文件)创建一个用于实现AutoCloseable接口的CAutoCloseable类。

代码中,AutoCloseable接口的实现非常简单,只需要实现close()方法即可。接下来,使用try()语句结构来调用CAutoCloseable对象,如下面的代码所示。

    public static void main(String[] args) {
        try(CAutoCloseable ac = new CAutoCloseable()) {
            System.out.println("使用对象");
        }
    }

示例中并没有调用CAutoCloseable对象中的close()方法,但是try()结构会自动调用它,代码执行结果如图5-12所示。

如果对象的使用出现异常呢?调用evil()方法试验一下,如下面的代码所示。

    public static void main(String[] args) {
    try(CAutoCloseable ac = new CAutoCloseable()) {
    ac.evil();
        }
    }

执行代码,可以看到,即使代码出错并且抛出异常,CAutoCloseable对象仍然能够自动调用close()方法,如图5-13所示。

图5-12 使用try()语句结构之一

图5-13 使用try()语句结构之二