try-catch-finally順序問題
使用帶整型返回值的函式探討try-catch-finally異常捕獲塊的執行順序:
分六步討論:
(1)無異常丟擲時,try塊有return語句,finally塊無return語句
(2)無異常丟擲時,try塊有return語句,finally塊無return語句,finally塊對try塊中該返回的值進行修改
(3)無異常丟擲時,try塊有return語句,finally塊有return語句
(4)有異常丟擲時,try塊有return語句,catch塊有return語句,finally塊有return語句
(5)有異常丟擲時,try塊有return語句,catch塊有return語句,finally塊無return語句
(6)有異常丟擲時,try塊有return語句,catch塊有return語句,finally塊無return語句,finally塊對catch塊中該返回的值進行修改。
具體步驟:對以上六種情況,分別向getNum(int a,int b)傳入a,b引數,得到num值,根據函式中的程式碼執行塊輸出語句以及最後得到的num的值判斷具體順序。
六種情況用於測試的程式碼如下:
(1)
package 異常捕獲塊執行順序; public class Main { public static void main(String[] args) { int a,b; a=2; b=1; int num = getNum(a,b); System.out.println(String.format("a的值是%d,b的值是%d,num的值是 %d",a,b,num)); } public static int getNum(int a,int b){ int num=0; try{ System.out.println("try塊被執行"); num = a/b; return num; }catch(Exception e){ System.out.println("catch塊被執行"); return -1; }finally{ System.out.println("finally塊被執行"); } } }
輸出結果:
分析:傳入a,b兩個數,a=2,b=1,得到的返回值num是2;函式中執行了try塊跟finally塊,此時返回值是a/b得到的商。
結論:無異常丟擲時,會先後執行try塊跟finally塊的程式碼。
(2)
package 異常捕獲塊執行順序; public class Main { public static void main(String[] args) { int a,b; a=2; b=1; int num = getNum(a,b); System.out.println(String.format("a的值是%d,b的值是%d,num的值是 %d",a,b,num)); } public static int getNum(int a,int b){ int num=0; try{ System.out.println("try塊被執行"); num = a/b; return num; }catch(Exception e){ System.out.println("catch塊被執行"); return -1; }finally{ System.out.println("finally塊被執行"); num++; } } }
輸出結果:
分析:函式中先執行try塊程式碼,得到num=a/b的結果為2,到return部分時先對該結果進行了一個暫存,再執行finally塊,num++,此時num為3,回到try塊,return剛才開始時暫存的結果2.
結論:try中return的值為暫存值,在finally塊對返回值num進行修改操作,不會影響到try裡的return值
(3)
package 異常捕獲塊執行順序;
public class Main {
public static void main(String[] args) {
int a,b;
a=2;
b=1;
int num = getNum(a,b);
System.out.println(String.format("a的值是%d,b的值是%d,num的值是 %d",a,b,num));
}
public static int getNum(int a,int b){
int num=0;
try{
System.out.println("try塊被執行");
num = a/b;
return num;
}catch(Exception e){
System.out.println("catch塊被執行");
return -1;
}finally{
System.out.println("finally塊被執行");
return num+1;
}
}
}
輸出結果:
分析:函式中執行了try塊-finally塊,得到的返回值不再是a/b的商,而是finally塊返回的num+1,即try塊該返回的值被finally塊覆蓋了。
結論:finally塊的return語句會覆蓋掉try塊中的return語句。
(4)
package 異常捕獲塊執行順序;
public class Main {
public static void main(String[] args) {
int a,b;
a=2;
b=0;
int num = getNum(a,b);
System.out.println(String.format("a的值是%d,b的值是%d,num的值是 %d",a,b,num));
}
public static int getNum(int a,int b){
int num=0;
try{
System.out.println("try塊被執行");
num = a/b;
return num;
}catch(Exception e){
System.out.println("catch塊被執行");
return -1;
}finally{
System.out.println("finally塊被執行");
return num+1;
}
}
}
輸出結果:
分析:函式中先執行try塊程式碼,在對num進行賦值操作時丟擲異常(除數不能為0,此時num仍為初始值0),被catch塊捕獲,執行catch塊程式碼,暫存catch塊需要返回的值,執行finally塊,返回num+1,覆蓋了catch塊的return語句。
結論:finally塊的return語句會將catch塊的return語句覆蓋。
(5)
package 異常捕獲塊執行順序;
public class Main {
public static void main(String[] args) {
int a,b;
a=2;
b=0;
int num = getNum(a,b);
System.out.println(String.format("a的值是%d,b的值是%d,num的值是 %d",a,b,num));
}
public static int getNum(int a,int b){
int num=0;
try{
System.out.println("try塊被執行");
num = a/b;
return num;
}catch(Exception e){
System.out.println("catch塊被執行");
num--;
return num;
}finally{
System.out.println("finally塊被執行");
}
}
}
輸出結果:
分析:先執行try塊,捕獲到異常時執行catch塊,到catch塊中return語句時執行finally塊程式碼,最後執行catch塊中的return語句。
結論:finally塊程式碼在catch返回值之前會被執行
(6)
package 異常捕獲塊執行順序;
public class Main {
public static void main(String[] args) {
int a,b;
a=2;
b=0;
int num = getNum(a,b);
System.out.println(String.format("a的值是%d,b的值是%d,num的值是 %d",a,b,num));
}
public static int getNum(int a,int b){
int num=0;
try{
System.out.println("try塊被執行");
num = a/b;
return num;
}catch(Exception e){
System.out.println("catch塊被執行");
num--;
return num;
}finally{
System.out.println("finally塊被執行");
num--;
}
}
}
輸出結果:
分析:先執行try塊,捕獲到異常時執行catch塊,num從0變為-1,到catch塊中return語句時先暫存num的值,再執行finally塊程式碼,num從-1變為-2,最後執行catch塊中的return語句,得到的結果是-1。原因是此時返回的num是之前暫存的num值,finally塊對num進行修改不影響之前暫存值的返回。
結論:finally塊修改catch塊中該返回的num時,不能影響到catch塊最終返回的值。
總結:
(1)無論try塊程式碼是否丟擲異常,最終都會執行finally塊程式碼。
(2)無異常丟擲時,執行try塊程式碼,到return語句時,會先將return的值進行一個暫存處理,再執行finally塊程式碼;如果finally塊有return語句,將會覆蓋掉try塊中的return語句;如果finally塊無return語句,將繼續回到try塊執行return語句,返回一開始在try塊中進行暫存的值。
(3)有異常丟擲時,先執行try塊程式碼,丟擲異常時跳轉到catch塊,執行catch塊程式碼;執行到catch塊的return語句時,先將該返回的值進行暫存,再執行finally塊語句;如果finally塊有return語句,將會覆蓋掉catch塊中的return語句;如果finally塊無return語句,將繼續回到catch塊執行return語句,返回剛才在catch塊執行return語句時暫存的值。
(4)如果在finally塊修改try/catch程式碼塊中return返回的變數的值,不會影響到try/catch塊最後的返回結果,因為try/catch塊最後返回的結果是原先暫存的值,與finally修改後的num無關。