try、catch、finally、return执行顺序超详解析(针对面试题)
有关try、catch、finally和return执行顺序的题目在面试题中可谓是频频出现。总结一下此类问题几种情况。
写在前面
- 不管try中是否出现异常,finally块中的代码都会执行;
- 当try和catch中有return时,finally依然会执行;
- finally是在return语句执行之后,返回之前执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,不管finally中的代码怎么样,返回的值都不会改变,仍然是之前保存的值),所以如果finally中没有return,即使对数据有操作也不会影响返回值,即如果finally中没有return,函数返回值是在finally执行前就已经确定了;
- finally中如果包含return,那么程序将在这里返回,而不是try或catch中的return返回,返回值就不是try或catch中保存的返回值了。
注:
- finally修改的基本类型是不影响 返回结果的。(传值)
- 修改list,map,自定义类等引用类型时,是影响返回结果的。(传址的)对象也是传址的
但是date类型经过测试是不影响的。
1、try{} catch(){}finally{} return;
按程序顺序运行,如果try中有异常,会执行catch中的代码块,有异常与否都会执行finally中的代码;最终返回。
2、try{ return; }catch(){} finally{} return;
- 先执行try块中return 语句(包括return语句中的表达式运算),但不返回;
- 执行finally语句中全部代码
- 最后执行try中return 返回
finally块之后的语句return不执行,因为程序在try中已经return。
示例:
public class Test{
public int add(int a,int b){
try{
return a+b;
}catch(Exception e){
System.out.println("catch语句块")
}finally{
System.out.println("finally语句块")
}
return 0;
}
public static void main(String argv[]){
Test test=new Test();
System.out.println("和是:"+test.add(9,34));
}
}
输出是
finally语句块 和是:43
至于为什么不是:和是 finally块43的原因:
System.out.println(“和是:”+test.add(9,34)); 这是进行字符串拼接是一个整体,所以首先是进入add方法,进去之后先不运算result,而是输出finally块。finally语句块,这句话先打印到控制台中。打印完后返回来执行try中的return得到43,此时再将结果与和是:拼接,输出和是:43.所以最终输出finally语句块 和是:43。
3、try{} catch(){return;} finally{} return;
程序先执行try,如果遇到异常执行catch块,最终都会执行finally中的代码块;
- 有异常:
- 执行catch中的语句和return中的表达式运算,但不返回
- 执行finally语句中全部代码,
- 最后执行catch块中return返回。 finally块后的return语句不再执行。
- 无异常:执行完try再finally再return…
示例1:有异常
public class Test04 {
public static void main(String[] args) {
System.out.println(test());
}
private static int test() {
int temp = 1;
try {
System.out.println(temp);
int i=1/0;
} catch (Exception e) {
System.out.println(temp);
return ++temp;
} finally {
++temp;
System.out.println(temp);
}
return temp;
}
}
输出:1132
先执行try中的打印temp=1;有异常,执行catch中的打印,然后执行return中的表达式运算,此时temp=2,并将结果保存在临时栈中,但不返回;执行finally中的语句,temp++,此时temp更新为3,同时打印,但因为finally中的操作不是return语句,所以不会去临时栈中的值,此时临时栈中的值仍然是2。finally中的执行完后,执行catch中的返回,即2。
示例2:无异常
public class Test04 {
public static void main(String[] args) {
System.out.println(test());
}
private static int test() {
int temp = 1;
try {
System.out.println(temp);
} catch (Exception e) {
System.out.println(temp);
return ++temp;
} finally {
++temp;
System.out.println(temp);
}
return ++temp;
}
}
输出:123
4、try{ return; }catch(){} finally{return;}
- 执行try块中的代码,和return语句(包括return语句中的表达式运算),但不返回(try中return的表达式运算的结果放在临时栈);
- 再执行finally块,
- 执行finally块(和return中的表达式运算,并更新临时栈中的值),从这里返回。
此时finally块的return值,就是代码执行完后的值
5、try{} catch(){return;}finally{return;}
- 执行try中的语句块,
- 有无异常
- 有异常:程序执行catch块中return语句(包括return语句中的表达式运算,,并将结果保存到临时栈),但不返回;
- 无异常:直接执行下面的
- 再执行finally块,
- 执行finally块return中的表达式运算,并更新临时栈中的值,并从这里返回。
示例1:无异常:
public class Test04 {
public static void main(String[] args) {
System.out.println(test());
}
private static int test() {
int temp = 1;
try {
System.out.println(temp);
} catch (Exception e) {
System.out.println(temp);
return ++temp;
} finally {
System.out.println(temp);
return ++temp;
}
}
}
输出:112
示例2:有异常
public class Test04 {
public static void main(String[] args) {
System.out.println(test());
}
private static int test() {
int temp = 1;
try {
System.out.println(temp);
int i=1/0;
} catch (Exception e) {
System.out.println(temp);
return ++temp;
} finally {
System.out.println(temp);
return ++temp;
}
}
}
输出:1123
6、try{ return;}catch(){return;} finally{return;}
程序执行try块中return语句(包括return语句中的表达式运算),但不返回;
- 有异常:
- 执行catch块中的语句和rreturn语句中的表达式运算,但不返回,结果保存在临时栈;
- 再执行finally块
- 执行finally块,有return,更新临时栈的值,并从这里返回。
- 无异常:
- 直接执行finally块
- 执行finally块,有return,更新临时栈的值,并从这里返回。
示例1:无异常:
package com.jc;
public class Test04 {
public static void main(String[] args) {
System.out.println(test());
}
private static int test() {
int temp = 1;
try {
System.out.println(temp);
// int i=1/0;
return ++temp;
} catch (Exception e) {
System.out.println(temp);
return ++temp;
} finally {
System.out.println(temp);
return ++temp;
}
}
}
输出:123
示例2:有异常
package com.jc;
public class Test04 {
public static void main(String[] args) {
System.out.println(test());
}
private static int test() {
int temp = 1;
try {
System.out.println(temp);
int i=1/0;
return ++temp;
} catch (Exception e) {
System.out.println(temp);
return ++temp;
} finally {
System.out.println(temp);
return ++temp;
}
}
}
输出:1123
7、try{ return;}catch(){return;} finally{其他}
程序执行try块中return语句(包括return语句中的表达式运算),但不返回;
- 有异常:
- 执行catch块中return语句(包括return语句中的表达式运算),但不返回;
- 再执行finally块
- 无异常:
- 再执行finally块
- 执行finally块,有return,从这里返回。
示例:
public class Test {
public static void main(String[] args) {
System.out.println(test());
}
private static int test() {
int temp = 1;
try {
System.out.println(temp);
return ++temp;
} catch (Exception e) {
System.out.println(temp);
return ++temp;
} finally {
++temp;
System.out.println(temp);
}
}
}
输出结果为132
执行顺序为:
- 输出try里面的初始temp:1;
- temp=2;
- 保存return里面temp的值:2;
- 执行finally的语句temp:3,输出temp:3;
- 返回try中的return语句,返回存在里面的temp的值:2;
- 输出temp:2。
finally代码块在return中间执行。return的值会被放入临时栈,然后执行finally代码块,如果finally中有return,会刷新临时栈的值,方法结束返回临时栈中的值。
最终结论:
- 任何执行try 或者catch中的return语句之后,在返回之前,如果finally存在的话,都会先执行finally语句,
- 如果finally中有return语句,那么程序就return了,所以finally中的return是一定会被return的,
- 编译器把finally中的return实现为一个warning。
- 不管有没有异常,finally代码块(包括finally中return语句中的表达式运算)都会在return之前执行
- 多个return(中的表达式运算)是按顺序执行的,多个return执行了一个之后,后面的return就不会执行。不管return是在try、catch、finally还是之外。