JAVA try catch finally return 执行顺序

JAVA try catch finally return 执行顺序

参考:https://www.cnblogs.com/superFish2016/p/6687549.html

一、结论

1、不管有没有出现异常,finally块中代码都会执行;
2、当try和catch中有return时,finally仍然会执行;
3、如果try、catch中有return语句,finally是在return后面的表达式运算后执行的。

  • 如果是基本数据类型、静态变量。(此时并没有返回finally中运算后的值,而是先把要返回的值保存起来,不管finally中的代码怎么样,返回的值都不会改变,仍然是之前保存的值),所以函数返回值是在finally执行前确定的;
  • 如果是引用数据类型,那么在finally中修改除包装类型,会对try、catch中返回的变量有影响。
    原因:JAVA基本数据类型、对象的引用以及方法参数存放在栈中,引用对象本身放在堆中。
    • 1 寄存器:最快的存储区,由编译器根据需求进行分配,我们在程序中无法控制。
    • 2 栈:存放基本类型的变量数据和对象的引用以及方法参数,但对象本身不存放在栈中,而是存放在堆(new出来的对象)或者常量池中(字符串常量对象存放在常量池中。)
    • 3 堆:存放所有new出来的对象。
    • 4 静态域:存放静态成员(static定义的)
    • 5 常量池:存放字符串常量和基本类型常量(public static final)。

4、尽量不要在finally中使用return语句,如果使用的话,会忽略try、catch中的返回语句,也会忽略try、catch中的异常,屏蔽了错误的发生。
5、finally中避免再次抛出异常,一旦finally中发生异常,代码执行将会抛出finally中的异常信息,try、catch中的异常将被忽略

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

二、return

return语句用来结束循环(函数),或返回一个函数的值。
1 return, 如果什么都不接的话,其实就是void类型函数的返回,返回后不再执行return后面的语句
如果函数执行成功返回0,不成功返回非0,一般情况下非0值常用-1来表示。
2 return 0:一般用在主函数结束时,表示程序正常终止,即告诉系统程序正常。
3 return -1::表示返回一个代数值,一般用在子函数结尾。表示程序异常终止,即告诉系统程序异常
4 return 1:与return -1相同。

三、代码实例

3.1基本数据类型和static类型

1、没有异常、没有return
	public static int testBasic1() {// 10
		int i = 1;
		try {
			i++;
			System.out.println("1try block, i = " + i);// 1try block, i = 2
		} catch (Exception e) {
			i++;
			System.out.println("1catch block i = " + i);// 没输出
		} finally {
			i = 10;
			System.out.println("1finally block i = " + i);// 1finally block i = 10
		}
		return i;// 10
	}
2、没有异常、有return

执行顺序:try return有一个返回值 执行finally

  • 在转去之前,try中先把要返回的结果存放到不同于i的局部变量中去,执行完finally之后,在从中取出返回结果,
  • 因此,即使finally中对变量i进行了改变,但是不会影响返回结果。
  • 它应该使用栈保存返回值。
	public static int testBasic2() {//不进入catch 返回的是2
		int i = 1;
		try {
			i++;
			System.out.println("2try block, i = " + i);//2try block, i = 2
			return i;
		} catch (Exception e) {
			i++;
			System.out.println("2catch block i = " + i);//没输出
			return i;
		} finally {
			i = 10;
			System.out.println("2finally block i = " + i);//2 finally block i = 10			
			// return i; 有警告
		}
	}
  • 代码顺序执行从try到finally,由于finally是无论如何都会执行的,所以try里的语句并不会直接返回。在try语句的return块中,return返回的引用变量并不是try语句外定义的引用变量i,而是系统重新定义了一个局部引用i’,这个引用指向了引用i对应的值,也就是2,即使在finally语句中把引用i指向了值10,因为return返回的引用已经不是i,而是i’,所以引用i的值和try语句中的返回值无关了。
3、有异常、有return

执行顺序:try-异常(try中异常后的不执行)-catch-- return有一个返回值 执行finally

  • 在转去之前,catch中先把要返回的结果存放到不同于i的局部变量中去,执行完finally之后,在从中取出返回结果,
  • 因此,即使finally中对变量i进行了改变,但是不会影响返回结果。
  • 它应该使用栈保存返回值。
	public static int testBasic3() {//进入catch 返回的是3
		int i = 1;
		try {
			i++;
			int j = 1/0;//抛出异常 算术运算异常
			System.out.println("3try block, i = " + i);//不执行
			return i;
		} catch (Exception e) {
			i++;
			System.out.println("3catch block i = " + i);//输出 3catch block i = 3
			return i;
		} finally {
			i = 10;
			System.out.println("3finally block i = " + i);//3finally block i = 10			
			// return i; //有警告
		}
	}
4、finally中有return
	public static int testBasic4() {//没异常不进入catch,有异常进入catch 两种情况返回的都是finally的10
		int i = 1;
		try {
			i++;
//			int j = 1/0;//抛出异常 算术运算异常
			System.out.println("4try block, i = " + i);//不抛出异常有输出4try block, i = 2 //抛出异常没输出
			return i;
		} catch (Exception e) {
			i++;
			System.out.println("4catch block i = " + i);//不抛出异常没输出 //抛出异常 有输出4catch block i = 3 
			return i;
		} finally {
			i = 10;
			System.out.println("4finally block i = " + i);//finally block i = 10			
			return i; //有警告 finally中不要有返回值
		}
	}
5、finally中有异常
	public static  int testBasic5(){//finally中有异常 控制台报错 Exception in thread "main" java.lang.ArithmeticException: / by zero
        int i = 1; 
        try{
            i++;
            Integer.parseInt(null);
            System.out.println("5try block, i = "+i);
            return i;
        }catch(Exception e){
            String.valueOf(null);
            System.out.println("5catch block i = "+i);
            return i;
        }finally{
            i = 10;
            int m = i / 0;//Exception in thread "main" java.lang.ArithmeticException: / by zero
            System.out.println("5finally block i = "+i);
        }
}

3.2引用数据类型

1、没有异常、finally无return。引用数据类型
	public static  List<Object> testWrap(){;//返回[try, finally]
        List<Object> list = new ArrayList<>();
        try{
            list.add("try");
            System.out.println("try block");//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 ");//finally block 
        }
	}
  • 可以看到,finally里对list集合的操作生效了,这是为什么呢。我们知道基本类型在栈中存储,而对于非基本类型是存储在堆中的,返回的是堆中的地址,因此内容被改变了。
2、有异常、finally无return。引用数据类型
	public static List<Object> testWrap2() {// 返回[try, catch, finally]

		List<Object> list = new ArrayList<>();
		try {
			list.add("try");
			int i = 1/0;
			System.out.println("try block");// 不输出
			return list;
		} catch (Exception e) {
			list.add("catch");
			System.out.println("catch block");//输出 catch block
			return list;
		} finally {
			list.add("finally");
			System.out.println("finally block ");// finally block
		}
	}
  • 可以看到,finally里对list集合的操作生效了,这是为什么呢。我们知道基本类型在栈中存储,而对于非基本类型是存储在堆中的,返回的是堆中的地址,因此内容被改变了。

总结

  • 举例:
  • 情况1:try{} catch(){}finally{} return;
    • 显然程序按顺序执行。
  • 情况2:try{ return; }catch(){} finally{} return;
    • 程序执行try块中return之前(包括return语句中的表达式运算)代码;
    • 再执行finally块,最后执行try中return;
    • finally块之后的语句return,因为程序在try中已经return所以不再执行。
  • 情况3:try{ } catch(){return;} finally{} return;
    • 程序先执行try,如果遇到异常执行catch块,
    • 有异常:则执行catch中return之前(包括return语句中的表达式运算)代码,
      再执行finally语句中全部代码,
      最后执行catch块中return. finally之后也就是4处的代码不再执行。
    • 无异常:执行完try再finally再return.
  • 情况4:try{ return; }catch(){} finally{return;}
    • 程序执行try块中return之前(包括return语句中的表达式运算)代码;
      再执行finally块,因为finally块中有return所以提前退出。
  • 情况5:try{} catch(){return;}finally{return;}
    • 没有异常:程序先执行try,然后执行finally,然后return;
    • 有异常:程序执行catch块中return之前(包括return语句中的表达式运算)代码;
      再执行finally块,因为finally块中有return所以提前退出(不执行catch中的return)。
  • 情况6:try{ return;}catch(){return;} finally{return;}
    • 程序执行try块中return之前(包括return语句中的表达式运算)代码;
    • 有异常:执行catch块中return之前(包括return语句中的表达式运算)代码;
      则再执行finally块,因为finally块中有return所以提前退出。
    • 无异常:则再执行finally块,因为finally块中有return所以提前退出。

最终结论:

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

猜你喜欢

转载自blog.csdn.net/xielong0509/article/details/83958814