Java学习笔记12——异常处理

当Java运行时系统接收到异常对象时,会寻找能处理这一异常的代码,并把当前异常对象交给其处理,这一过程成为捕获(catch)异常。如果Java运行时系统找不到可以捕获异常的代码,则运行时系统将终止,相应的Java程序也将推出。最终Java运行时系统将异常的相关信息输出(显示到System.err中)。

如何捕获异常呢?在Java中,捕获异常需要使用catch关键字,而后紧跟catch关键字的语句块就是异常处理代码。捕获异常犹如狩猎,无法发现猎物就谈不上捕获,所以在catch语句块的前面需要一个try语句来监听异常的抛出。try语句块就是try关键字跟随的语句块,其中是可能引发异常的代码。如下所示:

try{
    // 一些可能抛出异常的代码
}catch(TypeException1 e1){
    // 处理TypeException1类型异常的代码
}catch(TypeException2 e2){
    // 处理TypeException2类型异常的代码
}

上面代码演示了Java中异常处理的模式:先监听(try)后捕获(catch)。至于异常本身,它也是一个对象,有它自己的类型,所以我们的catch需要指定一个异常的类型。当程序在运行时期间出现一个错误时,Java运行时系统会在对象堆中创建一个异常类型的对象,并在指定的catch语句块中赋给匹配的异常类型的变量(上面代码中的e1和e2)。

完整的异常处理的语法结构是如下的形式:

try{
    //可能发生的异常代码块
}catch(TypeException1 e1){
    // 处理TypeException1类型的异常的代码
    // e1是TypeException1类型的异常对象
}catch(TypeException2 e2){
    // 处理TypeException2类型的异常的代码
    // e2是TypeException2类型的异常对象
...
}finally{
    // 此处代码块作为异常处理完成的收尾工作的代码块。
    // 请注意:不管try中的代码块正常执行还是抛出了异常,finally语句块中的代码都会被执行。
}

看如下的一段代码,来理解Java的异常处理。

package com.test;

public class ExcepTest {
    public int divide(int a,int b) {
        int c = a / b;
        return c;
    }

    public static void main(String[] args) {
        ExcepTest et = new ExcepTest();
        try{
            et.divide(5,0);
        }catch (ArithmeticException ae){
            System.out.println("除数不能为0");
        }catch (Exception e){
            System.out.println(e.toString()); // toString()方法输出异常对象的简短描述
        }finally {
            System.out.println("清理资源。");
        }

    }
}

(1)所有异常的基类都是Throwable,在这个类中有三个常用的方法,用于输出异常的相关信息,如下所示:

  • public String getMessage()  //返回异常对象的详细信息
  • public String toString()  //返回异常对象的简短描述
  • public void printStackTrace()  // 把异常对象的栈跟踪信息打印到标准的错误流(System.err对象)中。

修改上面处理ArithmeticException类型的异常代码块,可以如下:

package com.test;

public class ExcepTest {
    public int divide(int a,int b) {
        int c = a / b;
        return c;
    }

    public static void main(String[] args) {
        ExcepTest et = new ExcepTest();
        try{
            et.divide(5,0);
        }catch (ArithmeticException ae){
            System.err.println("getMessage:" + ae.getMessage());
            System.out.println("--------------------------");
            System.err.println("toString: " + ae.toString());
            System.out.println("--------------------------");
            // 异常对象的printStackTrace()本身就是输出异常的栈跟踪信息,因此不需要,也不能调用System.err.println()
            ae.printStackTrace();
        }catch (Exception e){
            System.out.println(e.toString()); // toString()方法输出异常对象的简短描述
        }finally {
            System.out.println("清理资源。");
        }

    }
}

(2)使用finally进行清理:在程序中经常会访问一些外部资源,如文件、数据库或者网络等,在资源访问结束后,我们会关闭或者释放资源。如果一切正常,代码顺序执行,那么资源释放的代码也会被执行。然而一旦发生异常,结果就变得不可预料了。

finally关键字后面的代码块将解决上面的问题。不管try语句块中代码是否抛出异常,finally语句块中的代码都将会被执行,因此比较适合在finally语句块中编写释放资源的代码。比如上面代码,发生“除数不能为0”的异常,捕获此类型的异常处理代码块中并没有输出“除数不能为0”信息的代码,但是finally语句块中有代码执行。

(3)在异常处理代码中定义了finally语句块,在捕获catch语句中即使有return语句,在执行该语句之前,Java运行时系统也会保证finally语句块中的代码被执行。

public class ExcepTest {
    public int divide(int a,int b) {
        int c = a / b;
        return c;
    }

    public static void main(String[] args) {
        ExcepTest et = new ExcepTest();
        try{
            et.divide(5,1);
            //
            return;

        }catch (ArithmeticException ae){
            System.err.println("getMessage:" + ae.getMessage());
            System.out.println("--------------------------");
            System.err.println("toString: " + ae.toString());
            System.out.println("--------------------------");
            // 异常对象的printStackTrace()本身就是输出异常的栈跟踪信息,因此不需要,也不能调用System.err.println()
            ae.printStackTrace();
        }catch (Exception e){
            System.out.println(e.toString()); // toString()方法输出异常对象的简短描述
        }finally {
            System.out.println("清理资源。");
        }

    }
}

上面代码,在try语句中执行et.divide(5,1),除数为1,代码正确执行,然后跟了一个return语句,但是运行上面代码依然会输出:"清理资源。",说明finally语句块依然被执行了。

(4)Exception类是所有异常类的基类,因此不管抛出何种异常,catch(Exception e)都能进行捕获,异常捕获机制是,只要发现了有匹配的就不会再执行后面的catch语句。因此,如果程序中把catch(Exception e)语句块放在紧挨try语句块,而在另外的处理其它异常的catch语句之前,Java编译器将提示错误。

(5)try语句并不一定要接catch语句,也可以只和finally语句一起使用,这通常用于在对异常的信息不感兴趣,也不需要对异常做进一步的处理的情况下,但是又需要做一些收尾的工作,以保证资源的合理释放等。

(6)finally语句并不是在所有情况下都会被调用执行,当程序中调用了System.exit(1)直接终止当前运行的Java虚拟机时,finally语句并不会被调用。

package com.test;

public class ExcepTest {
    public int divide(int a,int b) {
        int c = a / b;
        return c;
    }

    public static void main(String[] args) {
        ExcepTest et = new ExcepTest();
        try{
            et.divide(5,1);
            
            // 退出系统
            System.exit(1);

        }catch (ArithmeticException ae){
            System.err.println("getMessage:" + ae.getMessage());
            System.out.println("--------------------------");
            System.err.println("toString: " + ae.toString());
            System.out.println("--------------------------");
            // 异常对象的printStackTrace()本身就是输出异常的栈跟踪信息,因此不需要,也不能调用System.err.println()
            ae.printStackTrace();
        }catch (Exception e){
            System.out.println(e.toString()); // toString()方法输出异常对象的简短描述
        }finally {
            System.out.println("清理资源。");
        }

    }
}

运行上面代码,将不会显示任何信息,也就是finally语句块代码没有被执行。

(7)在finally语句块中执行的代码也有可能发生新的异常,可以在finally语句代码块中继续try...catch进行监听及捕获处理异常。

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值