Java:异常(细节版)

异常类体系

Java:异常(细节版)_第1张图片
Throwable是所有异常的基类,它有两个子类:Error和Exception。
Error表示系统错误或资源耗尽, 由Java系统自己使用,应用程序不应抛出和处理。比如图中列出的虚拟机错误(VirtualMacheError)及其子类内存溢出错误(OutOfMemoryError)和栈溢出错误(StackOverflowError)。
Exception表示应用程序错误, 它有很多子类,应用程序也可以通过继承Exception或其子类创建自定义异常,图中列出了三个直接子类:IOException(输入输出I/O异常),SQLException(数据库SQL异常),RuntimeException(运行时异常)。
RuntimeException(运行时异常)比较特殊,因为其他异常也是运行时产生的,它表示的实际含义是unchecked exception (未受检异常),相对而言,Exception的其他子类和Exception自身则是checked exception (受检异常),Error及其子类也是未受检异常。

  • 受检异常:
    受检异常必须出现在throws语句中,调用者必须处理,Java编译器会强制这一点,而未受检异常则没有这个要求。
    (受检异常表示程序本身没问题,但由于I/O、网络、数据库等其他不可预测的错误导致的异常,调用者应该进行适当处理。)

  • 未受检异常:
    未受检异常表示编程的逻辑错误,比如空指针异常。
    (出现这种异常,程序员应该检查程序代码的bug而不是想办法处理这种异常。)

自定义异常:

除了Java API中定义的异常类,我们也可以自己定义异常类,一般通过继承Exception或者它的某个子类,如果父类是RuntimeException或它的某个子类,则自定义异常也是未受检异常;如果是Exception或Exception的其他子类,则自定义异常是受检异常。

finally:
  • 如果没有异常发生,在try内的代码执行结束后执行。
  • 如果有异常发生且被catch捕获,在catch内的代码执行结束后执行。
  • 如果有异常发生但没被捕获,则在异常被抛给上层之前执行。

拓展:由于finally的这个特点,它一般用于释放资源,如数据库连接、文件流等。

finally细节:

如果在try或者catch语句内有return语句,则return语句在finally语句执行结束后才执行,但finally并不能改变返回值。
看如下代码:

    public static int test() {
        int ret = 0;
        try {
            return ret;
        }finally {
            ret = 2;
        }
    }

这个函数的返回值是0,而不是2。
实际的执行过程是:在执行到try内的return ret;语句前,会先将返回值ret保存在一个临时变量中,然后才执行finally语句,最后try再返回那个临时变量,finally中对ret的修改不会被返回。

如果在finally中也有return语句呢?
try和catch内的return会丢失,实际会返回finally中的返回值。finally中有return不仅会覆盖try和catch内的返回值,还会掩盖try和catch内的异常,就像异常没有发生一样,比如说:

    public static int test() {
        int ret = 0;
        try {
            int a = 5/0;
            return ret;
        }finally {
            return 2;
        }
    }

以上代码中,5/0会触发ArithmeticException,但是finally中有return语句,这个方法就会返回2,而不再向上传递异常了。

finally中不仅return语句会掩盖异常,如果finally中抛出了异常,则原异常就会被掩盖,看下面代码:

    public static int test() {
        try {
            int a = 5/0;
        }finally {
            throw new RuntimeException("hello world");
        }
    }

finally中抛出了RuntimeException,则原异常ArithmeticException就丢失了。

所以,一般而言,为避免混淆,应该避免在finally中使用return语句或者抛出异常,如果调用的其他代码可能抛出异常,则应该捕获异常并进行处理。

throw:

throw代表异常退出;就是抛出异常,它会触发Java的异常处理机制。

throws:

throws跟在方法的括号后面,可以声明多个异常,以逗号分隔。这个声明的含义是说,我这个方法内可能抛出这些异常,我没有进行处理,至少没有处理完,调用者必须进行处理。
这个声明没有说明具体什么情况会抛出什么异常,作为一个良好的实践,应该将这些信息用注释的方式进行说明,这样调用者才能更好的处理异常。

你可能感兴趣的:(Java)