java異常處理中的return和throw
如果把return和throw放在一起,直接會提示錯誤。"Unreachable statement"(無法被執行).
然而finally卻可以成功騙過編譯器讓兩者並存(是不是可以算是編譯器的一個小bug呢),結果是後執行的會覆蓋前者。
finally如果有return會覆蓋catch裡的throw,同樣如果finally裡有throw會覆蓋catch裡的return。
進而如果catch裡和finally都有return finally中的return會覆蓋catch中的。throw也是如此。
這樣就好理解一些了,retrun和throw都是使程式跳出當前的方法,自然就是衝突的。如果非要跳出兩次那麼後者會覆蓋前者。
-
public class T {
-
public T() {
-
}
-
boolean testEx() throws Exception {
-
boolean ret = true;
-
try {
-
ret = testEx1();
-
} catch (Exception e) {
-
System.out.println("testEx, catch exception");
-
ret = false;
-
throw e;
-
} finally {
-
System.out.println("testEx, finally; return value=" + ret);
-
return ret;
-
}
-
}
-
boolean testEx1() throws Exception {
-
boolean ret = true;
-
try {
-
ret = testEx2();
-
if (!ret) {
-
return false;
-
}
-
System.out.println("testEx1, at the end of try");
-
return ret;
-
} catch (Exception e) {
-
System.out.println("testEx1, catch exception");
-
ret = false;
-
throw e;
-
}
-
finally {
-
System.out.println("testEx1, finally; return value=" + ret);
-
return ret;
-
}
-
}
-
boolean testEx2() throws Exception {
-
boolean ret = true;
-
try {
-
int b = 12;
-
int c;
-
for (int i = 2; i >= -2; i--) {
-
c = b / i;
-
System.out.println("i=" + i);
-
}
-
return true;
-
} catch (Exception e) {
-
System.out.println("testEx2, catch exception");
-
ret = false;
-
throw e;
-
}
-
finally {
-
System.out.println("testEx2, finally; return value=" + ret);
-
//return ret;
-
}
-
}
-
public static void main(String[] args) {
-
T testException1 = new T();
-
try {
-
testException1.testEx();
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
}
-
}
i=2
i=1
testEx2, catch exception
testEx2, finally; return value=false
testEx1, catch exception
testEx1, finally; return value=false
testEx, finally; return value=false
try-catch-finally程式塊的執行流程
首先執行的是try語句塊中的語句,這時可能會有以下三種情況:
1. 如果try塊中所有語句正常執行完畢,那麼finally塊的居於就會被執行,這時分為以下兩種情況:
如果finally塊執行順利,那麼整個try-catch-finally程式塊正常完成。
如果finally塊由於原因R突然中止,那麼try-catch-finally程式塊的結局是“由於原因R突然中止(completes abruptly)”
2. 如果try語句塊在執行過程中碰到異常V,這時又分為兩種情況進行處理:
如果異常V能夠被與try相應的catch塊catch到,那麼第一個catch到這個異常的catch塊(也是離try最近的一個與異常V匹配的catch塊)將被執行;這時就會有兩種執行結果:
如果catch塊執行正常,那麼finally塊將會被執行,這時分為兩種情況:
如果finally塊執行順利,那麼整個try-catch-finally程式塊正常完成。
如果finally塊由於原因R突然中止,那麼try-catch-finally程式塊的結局是“由於原因R突然中止(completes abruptly)”
如果catch塊由於原因R突然中止,那麼finally模組將被執行,分為兩種情況:
如果如果finally塊執行順利,那麼整個try-catch-finally程式塊的結局是“由於原因R突然中止(completes abruptly)”。
如果finally塊由於原因S突然中止,那麼整個try-catch-finally程式塊的結局是“由於原因S突然中止(completes abruptly)”,原因R將被拋棄。
雖然我們在testEx2中使用throw e丟擲了異常,但是由於testEx2中有finally塊,而finally塊的執行結果是complete abruptly的。因為return也是一種導致complete abruptly的原因之一,所以整個try-catch-finally程式塊的結果是“complete abruptly”,所以在testEx1中呼叫testEx2時是捕捉不到testEx1中丟擲的那個異常的,而只能將finally中的return 結果獲取到。當然這種情況是可以避免的,以testEx2為例:如果你一定要使用finally而且又要將catch中 throw的e在testEx1中被捕獲到,那麼你去掉testEx2中的finally中的return就可以了。如果將testEx2()中的
-
finally {
-
System.out.println("testEx2, finally; return value=" + ret);
-
//return ret;
-
}
修改為
-
finally {
-
System.out.println("testEx2, finally; return value=" + ret);
-
return ret;
-
}
那麼執行結果:
i=2
i=1
testEx2, catch exception
testEx2, finally; return value=false
testEx1, finally; return value=false
testEx, finally; return value=false
try-catch-finally程式塊中的return
從上面的try-catch-finally程式塊的執行流程以及執行結果一節中可以看出無論try或catch中發生了什麼情況,finally都是會被執行的,那麼寫在try或者catch中的return語句也就不會真正的從該函式中跳出了,它的作用在這種情況下就變成了將控制權(語句流程)轉到 finally塊中;這種情況下一定要注意返回值的處理。
例如,在try或者catch中return false了,而在finally中又return true,那麼這種情況下不要期待你的try或者catch中的return false的返回值false被上級呼叫函式獲取到,上級呼叫函式能夠獲取到的只是finally中的返回值,因為try或者catch中的return 語句只是轉移控制權的作用。