Java中的异常处理机制浅析

2016-12-04  本文已影响66人  yang2yang

先上图


Java异常类层次结构图.png

需要注意的是ErrorRuntimeException都是未检查异常,也就是说不需要使用try...catch来进行捕获。但是IOException属于检查型异常是必须使用try...catch来进行捕获或者将其抛出到外层调用者函数。

举个栗子

public class TTestException {

    public void a() throws MyException {
        throw new MyException();
    }

    public void b(){
        try {
            throw new MyException();
        } catch (MyException e) {
            e.printStackTrace();
        }
    }

    public void c(){
        String s = null;
        System.out.println(s.length());
    }

    public static void main(String[] args) {
        TTestException tTestException = new TTestException();
        try {
            tTestException.a();
        } catch (MyException e) {
            e.printStackTrace();
        }

        tTestException.b();

        System.out.println("After b() before c()");

        tTestException.c();

        System.out.println("After c()");
    }

}

这个例子里面ab都会抛出检查型异常,但是a是把异常再次向调用者抛出,b是直接在函数内部就进行处理了。

再观察外层调用会抛出检查型异常的情况,调用a的时候是必须对其进行处理的,要不就是try...catch或者就是再次向外抛出,这里就应该明白一个道理就是一个检查型异常是必须在程序的某个层次中进行处理的,既然程序中进行了处理,那么这个检查型异常是不会导致程序停止的,调用b函数的时候,因为b内部已经进行了处理,那么就可以正常的调用。

再来看看调用c的情况,因为字符串s是null,所以尝试获得一个length的时候,是会发生空指针异常的,但是这个空指针异常又和上面的MyException不同,空指针异常是个非检查型异常,Java没有规定必须处理,可以处理,也可以不处理。

如果不进行处理,那么一但抛出这个异常,就是Java就会认为是程序逻辑有问题,从而停止这个正在运行的程序,所以在调用c之后的打印函数,是不会打印出来东西的。但是为了保证程序不会因为这种逻辑异常不会停止,也进行try...catch的话,那么也就是处理了这个异常,就不会被强制停止线程的运行。

关于自定义异常

自定义异常一般是继承于Exception类。可以看一下Exception的源代码。

public class Exception extends Throwable {
    static final long serialVersionUID = -3387516993124229948L;

    public Exception() {
        super();
    }

    public Exception(String message) {
        super(message);
    }


    public Exception(String message, Throwable cause) {
        super(message, cause);
    }


    public Exception(Throwable cause) {
        super(cause);
    }

    protected Exception(String message, Throwable cause,
                        boolean enableSuppression,
                        boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

删掉一些注释就会妨碍吸纳,其实这个Exception类什么都没有,都是针对不同参数的构造函数,但是构造函数其实都是直接调用的是Throwable的构造函数,也没有做一些其他的事情。

那么既然是这样的话,那么是不是自定义的异常类,直接继承Throwable和继承Exception效果其实一样的呢?应该是的。

本来还想再看一下Throwable的源代码的,的确也看了,但是看到一些native的方法就不想贴出来了。

下面就是一个很经典的自定义的异常类。

public class MyException extends Exception {

    public MyException() {
    }
    //这里可以不用显示地调用super(),因为函数里面没有其他东西
    //如果有其他东西的话,那么还是需要使用super()进行显示调用的
    public MyException(String msg) {
    }
}

其实自定义的异常类,最重要的是异常的名字,通过自定义异常,然后抛出自定义的异常,可以清楚地通过异常的名字,看到具体是什么异常被抛出了,从而清楚地定位问题。

题外话

最近在进行Web开发的时候一直在想一个问题,比如有个查询数据库的操作,这个查询操作,可能会返回null,也可能会返回n条纪录(如果为null的话,那么很有可能在外层引起空指针异常),那么如果返回null的话,是在底层就将其使用异常机制抛出,强行告诉外层进行异常捕获,还是说什么都不做,在外层通过判断是否为null进行处理呢?

参考

上一篇下一篇

猜你喜欢

热点阅读