finally、catch和return,你真的会用吗?

标签: finally/return  异常/错误  try/finally/return

1.先简单介绍一下Java中的错误(Error)和异常(Exception)

在java.lang包中有一个java.lang.Throwable类,这个类是所有错误和异常的父类。

Error:

    是Java中所有错误的父类,一般是与虚拟机相关的问题,如系统崩溃,虚拟机错误,动态链接失败等。对于这种任务,通常应用程序无法处理这类错误,也不需要开发人员处理,故应用程序不需要使用cath来捕获Error对象,也无须在throws子句中声明该方法可能出现的Error错误。

Exception:

        又分为编译异常(checkedException)和运行异常(RuntimeException)这两种异常。

        编译异常:在进行编译时就知道会不会发生异常,如果不对这些异常进行抛出,捕获的话就不能通过编译,比如使用Java的io读流取文件的时候,可能会出现文件不存在的情况;还有调用阻塞方法(wait,sleep),中断阻塞就会在外部调用interrupt,那么就会抛出InterruptedException异常。对于这些异常,系统都是做最坏的打算,必须手动去处理(捕获或者抛出)。否则是无法正常通过编译器的,这种异常才需要try-catch。

        运行异常:在运行时会可能会出现的异常,之前不知道。比如数组下标越界(ArrayIndexOutOfBoundsException),空指针异常(NullpointerException),除数为0(ArithmeticException)对于这些异常是否抛出,由用户自己决定,因为本来就不知道会不会出现异常,并不强制要去一定处理。


异常处理过程

  有两种方式:try{ }catch{ }finally{ }和throws

     把会出现的异常程序放在try块中,出现异常中断当前代码去执行catch{ }中内容,最后执行finally。    

    throws关键字一般用于方法名后面,一般是开发者不确定会出现什么异常的情况可能有多种,这时加个throws关键字抛出。对于调用这个方法的开发者必须捕获这个异常或者继续throws这个异常,把这个异常传递下去,交给其父亲去处理。

    throw一般用于方法中,抛出用户自定义的异常如 throw new MyException("用户自定义异常")

2. finally、return:

    a. finally中的代码总是会执行吗?

答:no,(两种情况)如果一个方法内在执行try{}语句之前就已经return了,那么finally语句不会执行了。因为根本没有进入try语句中。 如果在一个try语句中调用System.exit(0);方法,那么就会退出当前java虚拟机,那么finally也就没有执行的机会了。(当然,还有极端的,就是在执行到try突然杀死了,断电了)

    b、finally在return之前执行还是在return之后执行?

 答:是在return中间执行


public class Test {
    public static void main(String[] args) {
        System.out.println(method());
    }

    public static int method(){
        int x = 1;
        try {
            return x;
        } catch (Exception e){
            return 0;
        }finally {
            System.out.println("Test");
            ++ x;
        }
    }
}

结果:先输出Test,下一行为1

执行过程:

        首先执行到return方法,就会返回相应的值,把值存在临时栈中。此时临时栈为1。但是并不会立马返回,而是还要执行finally方法,执行完后,调用return,此时不是返回值,而是告诉主程序已经执行完了,可以执行其他方法。但是此时临时栈还是保存的是栈中的值为1。

  

public class Test {
    public static void main(String[] args) {
        System.out.println(method());
    }
    public static int method(){
        try {
            return 1;
         // System.out.println("Test");
        } catch (Exception e){
            return 0;
        }finally {
            return 2;
        }
     //  System.out.println("Test");
    }
}

结果:2

执行过程:

        执行到return 1时,临时栈为1,接着执行finally中的return 2, 会覆盖之前的1,所以返回2。

注意:上文的那两句输出程序都到达不了。

没看懂? 再来两道:

public class Test1 {
    public static void main(String[] args) {
        System.out.println(method());
    }

    public static int method(){
        int a = 0;
        try {
            a = 1;
            return a;
        }finally {
            a = 2;
            System.out.println(a);
        }
    }
}

输出: 2,1

a = 1存到一个临时栈中,程序不会立即返回,在执行a = 2,时仅仅是覆盖了a的值,但是没有去更新临时栈中返回的那个值。如果在finally中输出a的值,则是覆盖后的值。

public class Test1 {
    public static void main(String[] args) {
        System.out.println(method());
    }

    public static int method(){
        int a = 0;
        try {
            a = 1;
            return a;
        }finally {
            a = 2;
            return a;
        }
    }
}
/** 
output: 2
*/

        finally中也有一个return,此时就会去更新临时栈中的值,执行完finally之后,就会通知主程序返回了,即将临时站中的值取出来。(所以应该知道,finally中最好不要有return,否则程序会提前退出,返回值不是try,catch保存的返回值。)


总结:

    1,finally一定会执行,无论是否try..catch。

    2,finally前try{ }有return,会先执行return,并保存下来,再执行finally块,最后执行return。

    3,finally前try{ }有return,会先执行return,把值保存下来,再执行finally块的return,把值覆盖掉,并返回。

(当然catch块有return是一样的,关键在于return保存在临时栈中,并不立马结束,而是去执行finally块。)

版权声明:本文为Jae_Wang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Jae_Wang/article/details/80208681