• 有return的情况下try catch finally的执行顺序


    有return的情况下try catch finally的执行顺序(最有说服力的总结)

    结论:

    • 1、不管有没有出现异常,finally块中代码都会执行;
    • 2、当try和catch中有return时,finally仍然会执行;
    • 3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,不管finally
      中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的(集合list除外);
    • 4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。

    举例:

    情况1:try{} catch(){}finally{} return;

    显然程序按顺序执行。
    ```Java public class TestReturn { public static void main(String[]args) { int result = TestReturn.testReturn1(); System.out.println("testReturn的返回结果为:" + result); }
    public static int testReturn1() {
    	int i = 1;
    	try {
    		System.out.println("进入try语句啦," + i);
    	} catch (Exception e) {
    		System.out.println("进入catch语句啦," + i);
    	} finally {
    		System.out.println("进入finally语句啦," + i);
    	}
    	return i;
    }
    

    }

    进入try语句啦,1
    进入finally语句啦,1
    testReturn的返回结果为:1
    
    ### 情况2:try{ return; }catch(){} finally{} return;
    <blockquote>程序执行try块中return之前(包括return语句中的表达式运算)代码;
    再执行finally块,最后执行try中return;
    finally块之后的语句return,因为程序在try中已经return所以不再执行。
    </blockquote>
    
    ```Java
    public class TestReturn {
    	public static void main(String[]args) {
    		int result = TestReturn.testReturn2();
    		System.out.println("testReturn的返回结果为:" + result);
    	}
    	
    	public static int testReturn2() {
    		int i = 1;
    		try {
    			System.out.println("进入try语句啦," + i);
    			return ++i;
    		} catch (Exception e) {
    			System.out.println("进入catch语句啦," + i);
    		} finally {
    			System.out.println("进入finally语句啦," + i);
    		}
    		return ++i;
    	}	
    
    }
    

    进入try语句啦,1
    进入finally语句啦,2
    testReturn的返回结果为:2

    情况3:try{ } catch(){return;} finally{} return;

    程序先执行try,如果遇到异常执行catch块。 有异常:则执行catch中return之前(包括return语句中的表达式运算)代码,再执行finally语句中全部代码,最后执行catch块中return. finally之后也就是4处的代码不再执行。 无异常:执行完try再finally再return。
    public class TestReturn {
    	public static void main(String[]args) {
    		int result = TestReturn.testReturn3_1();
    		System.out.println("testReturn的返回结果为:" + result);
    	}
    	
    	public static int testReturn3_1() {
    		int i = 1;
    		try {
    			System.out.println("进入try语句啦," + i);
    			i = 5 / 0;
    		} catch (Exception e) {
    			System.out.println("进入catch语句啦," + i);
    			return ++i;
    		} finally {
    			System.out.println("进入finally语句啦," + i);
    		}
    		return ++i;
    	}
    
    }
    

    进入try语句啦,1
    进入catch语句啦,1
    进入finally语句啦,2
    testReturn的返回结果为:2

    public class TestReturn {
    	public static void main(String[]args) {
    		int result = TestReturn.testReturn3_2();
    		System.out.println("testReturn的返回结果为:" + result);
    	}
    	
    	public static int testReturn3_2() {
    		int i = 1;
    		try {
    			System.out.println("进入try语句啦," + i);
    		} catch (Exception e) {
    			System.out.println("进入catch语句啦," + i);
    			return ++i;
    		} finally {
    			System.out.println("进入finally语句啦," + i);
    		}
    		return ++i;
    	}
    
    }
    

    进入try语句啦,1
    进入finally语句啦,1
    testReturn的返回结果为:2

    情况4:try{ return; }catch(){} finally{return;}

    程序执行try块中return之前(包括return语句中的表达式运算)代码; 再执行finally块,因为finally块中有return所以提前退出。
    public class TestReturn {
    	public static void main(String[]args) {
    		int result = TestReturn.testReturn4();
    		System.out.println("testReturn的返回结果为:" + result);
    	}
    	
    	@SuppressWarnings("finally")
    	public static int testReturn4() {
    		int i = 1;
    		try {
    			System.out.println("进入try语句啦," + i);
    			return ++i;
    		} catch (Exception e) {
    			System.out.println("进入catch语句啦," + i);
    		} finally {
    			System.out.println("进入finally语句啦," + i);
    			return ++i;
    		}
    	}
    
    }
    

    进入try语句啦,1
    进入finally语句啦,2
    testReturn的返回结果为:3

    情况5:try{} catch(){return;}finally{return;}

    程序执行catch块中return之前(包括return语句中的表达式运算)代码; 再执行finally块,因为finally块中有return所以提前退出。
    public class TestReturn {
    	public static void main(String[]args) {
    		int result = TestReturn.testReturn5();
    		System.out.println("testReturn的返回结果为:" + result);
    	}
    	
    	@SuppressWarnings("finally")
    	public static int testReturn5() {
    		int i = 1;
    		try {
    			System.out.println("进入try语句啦," + i);
    			i = 5 / 0;
    		} catch (Exception e) {
    			System.out.println("进入catch语句啦," + i);
    			return ++i;
    		} finally {
    			System.out.println("进入finally语句啦," + i);
    			return ++i;
    		}
    	}
    
    }
    

    进入try语句啦,1
    进入catch语句啦,1
    进入finally语句啦,2
    testReturn的返回结果为:3

    情况6:try{ return;}catch(){return;} finally{return;}

    程序执行try块中return之前(包括return语句中的表达式运算)代码。 有异常:执行catch块中return之前(包括return语句中的表达式运算)代码; 则再执行finally块,因为finally块中有return所以提前退出。 无异常:则再执行finally块,因为finally块中有return所以提前退出。
    public class TestReturn {
    	public static void main(String[]args) {
    		int result = TestReturn.testReturn6();
    		System.out.println("testReturn的返回结果为:" + result);
    	}
    
    	@SuppressWarnings("finally")
    	public static int testReturn6() {
    		int i = 1;
    		try {
    			System.out.println("进入try语句啦," + i);
    			i = 5 / 0;
    			return ++i;
    		} catch (Exception e) {
    			System.out.println("进入catch语句啦," + i);
    			return ++i;
    		} finally {
    			System.out.println("进入finally语句啦," + i);
    			return ++i;
    		}
    	}	
    
    }
    

    进入try语句啦,1
    进入catch语句啦,1
    进入finally语句啦,2
    testReturn的返回结果为:3

    最终结论:

    任何执行try或者catch中的return语句之前,都会先执行finally语句,如果finally存在的话。如果finally中有return语句,那么程序就return了,所以finally中的return是一定会被return的,编译器把finally中的return实现为一个warning。

    整体代码:

    public class TestReturn {
    	public static void main(String[] args) {
    		System.out.println("testReturn的返回结果为:" + TestReturn.testReturn1());
    		System.out.println("-------------------------");
    		System.out.println("testReturn的返回结果为:" + TestReturn.testReturn2());
    		System.out.println("-------------------------");
    		System.out.println("testReturn的返回结果为:" + TestReturn.testReturn3_1());
    		System.out.println("-------------------------");
    		System.out.println("testReturn的返回结果为:" + TestReturn.testReturn3_2());
    		System.out.println("-------------------------");
    		System.out.println("testReturn的返回结果为:" + TestReturn.testReturn4());
    		System.out.println("-------------------------");
    		System.out.println("testReturn的返回结果为:" + TestReturn.testReturn5());
    		System.out.println("-------------------------");
    		System.out.println("testReturn的返回结果为:" + TestReturn.testReturn6());
    	}
    
    	public static int testReturn1() {
    		int i = 1;
    		try {
    			System.out.println("进入try语句啦," + i);
    		} catch (Exception e) {
    			System.out.println("进入catch语句啦," + i);
    		} finally {
    			System.out.println("进入finally语句啦," + i);
    		}
    		return i;
    	}
    
    	public static int testReturn2() {
    		int i = 1;
    		try {
    			System.out.println("进入try语句啦," + i);
    			return ++i;
    		} catch (Exception e) {
    			System.out.println("进入catch语句啦," + i);
    		} finally {
    			System.out.println("进入finally语句啦," + i);
    		}
    		return ++i;
    	}
    
    	public static int testReturn3_1() {
    		int i = 1;
    		try {
    			System.out.println("进入try语句啦," + i);
    			i = 5 / 0;
    		} catch (Exception e) {
    			System.out.println("进入catch语句啦," + i);
    			return ++i;
    		} finally {
    			System.out.println("进入finally语句啦," + i);
    		}
    		return ++i;
    	}
    
    	public static int testReturn3_2() {
    		int i = 1;
    		try {
    			System.out.println("进入try语句啦," + i);
    		} catch (Exception e) {
    			System.out.println("进入catch语句啦," + i);
    			return ++i;
    		} finally {
    			System.out.println("进入finally语句啦," + i);
    		}
    		return ++i;
    	}
    
    	@SuppressWarnings("finally")
    	public static int testReturn4() {
    		int i = 1;
    		try {
    			System.out.println("进入try语句啦," + i);
    			return ++i;
    		} catch (Exception e) {
    			System.out.println("进入catch语句啦," + i);
    		} finally {
    			System.out.println("进入finally语句啦," + i);
    			return ++i;
    		}
    	}
    
    	@SuppressWarnings("finally")
    	public static int testReturn5() {
    		int i = 1;
    		try {
    			System.out.println("进入try语句啦," + i);
    			i = 5 / 0;
    		} catch (Exception e) {
    			System.out.println("进入catch语句啦," + i);
    			return ++i;
    		} finally {
    			System.out.println("进入finally语句啦," + i);
    			return ++i;
    		}
    	}
    
    	@SuppressWarnings("finally")
    	public static int testReturn6() {
    		int i = 1;
    		try {
    			System.out.println("进入try语句啦," + i);
    			i = 5 / 0;
    			return ++i;
    		} catch (Exception e) {
    			System.out.println("进入catch语句啦," + i);
    			return ++i;
    		} finally {
    			System.out.println("进入finally语句啦," + i);
    			return ++i;
    		}
    	}
    
    }
    

    进入try语句啦,1
    进入finally语句啦,1
    testReturn的返回结果为:1

    进入try语句啦,1
    进入finally语句啦,2
    testReturn的返回结果为:2

    进入try语句啦,1
    进入catch语句啦,1
    进入finally语句啦,2
    testReturn的返回结果为:2

    进入try语句啦,1
    进入finally语句啦,1
    testReturn的返回结果为:2

    进入try语句啦,1
    进入finally语句啦,2
    testReturn的返回结果为:3

    进入try语句啦,1
    进入catch语句啦,1
    进入finally语句啦,2
    testReturn的返回结果为:3

    进入try语句啦,1
    进入catch语句啦,1
    进入finally语句啦,2
    testReturn的返回结果为:3

    下面是个测试程序

    public class FinallyTest {
    	public static void main(String[] args) {
    		System.out.println(FinallyTest.test());
    	}
    
    	public static int test() {
    		int x = 1;
    		try {
    			x++;
    			return x;
    		} finally {
    			++x;
    		}
    	}
    }
    

    结果是2。

    在try语句中,在执行return语句时,要返回的结果已经准备好了,就在此时,程序转到finally执行了。 在转去之前,try中先把要返回的结果存放到不同于x的局部变量中去,执行完finally之后,在从中取出返回结果, 因此,即使finally中对变量x进行了改变,但是不会影响返回结果。 它应该使用栈保存返回值。

      在网上看到一些异常处理的面试题,试着总结一下,先看下面代码,把这个方法在main中进行调用打印返回结果,看看结果输出什么。

    public static  int testBasic(){
        int i = 1; 
        try{
            i++;
            System.out.println("try block, i = "+i);
        }catch(Exception e){
            i ++;
            System.out.println("catch block i = "+i);
        }finally{
            i = 10;
            System.out.println("finally block i = "+i);
        }
        return i;
    }
    
    没错,会按照顺序执行,先执行try内代码段,没有异常的话进入finally,最后返回,那么输出如下: try block, i = 2 finally block i = 10

    这个没有问题,如果我们把return语句放入try catch里又会怎么样呢?

    public static  int testBasic(){
        int i = 1; 
        try{
            i++;
            System.out.println("try block, i = "+i);
            return i;
        }catch(Exception e){
            i ++;
            System.out.println("catch block i = "+i);
            return i;
        }finally{
            i = 10;
            System.out.println("finally block i = "+i);
        }
    }
    

    输出结果是:
    try block, i = 2
    finally block i = 10

    代码顺序执行从try到finally,由于finally是无论如何都会执行的,所以try里的语句并不会直接返回。 在try语句的return块中,return返回的引用变量并不是try语句外定义的引用变量i,而是系统重新定义了一个局部引用i’,这个引用指向了引用i对应的值,也就是2,即使在finally语句中把引用i指向了值10,因为return返回的引用已经不是i,而是i',所以引用i的值和try语句中的返回值无关了。

    但是,这只是一部分,如果把i换成包装类型而不是基本类型呢,来看看输出结果怎样,示例如下:

    public static  List<Object> testWrap(){
        List<Object> list = new ArrayList<>();
        try{
            list.add("try");
            System.out.println("try block");
            return list;
        }catch(Exception e){
            list.add("catch");
            System.out.println("catch block");
            return list;
        }finally{
            list.add("finally");
            System.out.println("finally block ");
        }
    }
    

    打印结果如下:
    try block
    finally block

    可以看到,finally里对list集合的操作生效了,这是为什么呢。我们知道基本类型在栈中存储,而对于非基本类型是存储在堆中的,返回的是堆中的地址,因此内容被改变了。

    好了,现在我们在finally里加一个return,看看语句是从哪里返回的。

    @SuppressWarnings("finally")
    public static  int testBasic(){
        int i = 1; 
        try{
            i++;
            System.out.println("try block, i = "+i);
            return i;
        }catch(Exception e){
            i ++;
            System.out.println("catch block, i = "+i);
            return i;
        }finally{
            i = 10;
            System.out.println("finally block, i = "+i);
            return i;
        }
    }
    

    输出结果如下:
    try block, i = 2
    finally block i = 10

      可以看到,是从finally语句块中返回的。可见,JVM是忽略了try中的return语句。但IDE中会对finally中加的return有黄色警告提示,这是为什么呢,在try里加入一行会执行异常的代码,如下:

    @SuppressWarnings("finally")
    public static  int testBasic(){
        int i = 1; 
        try{
            i++;
            int m = i / 0 ;
            System.out.println("try block, i = "+i);
            return i;
        }catch(Exception e){
            i ++;
            System.out.println("catch block, i = "+i);
            return i;
        }finally{
            i = 10;
            System.out.println("finally block, i = "+i);
            return i;
        }
    }
    

    打印结果如下:
    catch block, i = 3
    finally block, i = 10

    可以看到,因为finally中有return语句,try、catch中的异常被消化掉了,屏蔽了异常的发生,这与初期使用try、catch的初衷是相违背的,因此编译器也会提示警告。

    那如果在finally中有异常发生,会对try、catch中的异常有什么影响呢?

    public static  int testBasic(){
        int i = 1; 
        try{
            i++;
            Integer.parseInt(null);
            System.out.println("try block, i = "+i);
            return i;
        }catch(Exception e){
            String.valueOf(null);
            System.out.println("catch block i = "+i);
            return i;
        }finally{
            i = 10;
            int m = i / 0;
            System.out.println("finally block i = "+i);
        }
    }
    

    这里我们在try、catch里强行加上异常语句,打印结果如下:

    Exception in thread "main" java.lang.ArithmeticException: / by zero
        at Java基础加强.异常.seq.TestException.testBasic(TestException.java:20)
        at Java基础加强.异常.seq.TestException.main(TestException.java:5)
    
    这个提示表示的是finally里的异常信息,也就是说一旦finally里发生异常,try、catch里的异常信息即被消化掉了,也达不到异常信息处理的目的。

    总结以上测试:

    • 1、finally语句总会执行。

    • 2、如果try、catch中有return语句,finally中没有return,那么在finally中修改除包装类型和静态变量、全局变量以外的数据都不会对try、catch中返回的变量有任何的影响。(包装类型、静态变量会改变、全局变量)

    • 3、尽量不要在finally中使用return语句,如果使用的话,会忽略try、catch中的返回语句,也会忽略try、catch中的异常,屏蔽了错误的发生。

    • 4、finally中避免再次抛出异常,一旦finally中发生异常,代码执行将会抛出finally中的异常信息,try、catch中的异常将被忽略。

    所以在实际项目中,finally常常是用来关闭流或者数据库资源的,并不额外做其他操作。

    参考:
    https://blog.csdn.net/xx326664162/article/details/50266995
    https://www.cnblogs.com/superFish2016/p/6687549.html

  • 相关阅读:
    JVM发生OOM调优
    行云创新完成B轮融资,阿里云独家投资
    行云创新直播回顾:DDD“爱”上Dapr
    如何通过Dapr快速实现DDD?
    通过Dapr快速落地DDD,实现高并发
    上K8s,研发团队如何从容一点?
    直播来了!等你围观!聊聊服务网格那些事儿
    服务网格出现流量故障该咋办?SolarMesh发布重大功能
    mysql 授权问题
    Centos Mysql5.7 安装
  • 原文地址:https://www.cnblogs.com/hgnulb/p/9696132.html
Copyright © 2020-2023  润新知