火線團隊推出【火線解碼】系列文章,每一篇解釋一種不規(guī)范的代碼寫法,用較短的篇幅讓大家快速的了解代碼規(guī)范問題。
001.避免在finally語句塊中使用return語句
錯誤的代碼示例:
public class Bar {
public String foo() {
try {
doSomething();
} catch (Exception e) {
throw e;
} finally {
return "OK"; //觸發(fā)規(guī)則
}
}
}
以上代碼中的try-catch-finally是Java代碼中很常見的寫法,其中finally語句塊作為確定會執(zhí)行的語句塊,一般多用于資源的清理操作。但是文中的finally語句塊中使用了return語句,是需要避免的寫法。
為什么?
舉例說明:
public class Test02 {
public static void main(String[] args) {
int b=doSomething();
System.out.println("b="+b);
}
public static int doSomething() {
int a = 10;
try {
a= 8/0;
} catch (ArithmeticException e) {
System.out.println("捕獲到異常");
//e.printStackTrace();
throw e;
} finally {
return a;//錯誤的寫法
}
//return a;//正確的寫法
}
}
代碼中在doSomething()方法中設(shè)置了一個常見的除0異常。當執(zhí)行main方法時,我們預(yù)期應(yīng)該輸出“捕獲到異?!?,并拋出異常的詳細信息。
實際該代碼輸出了“捕獲到異?!币约啊癰=10”,沒有拋出異常信息。根據(jù)輸出信息“捕獲到異?!闭Z句說明try-catch語句塊實際已經(jīng)執(zhí)行完成,但是輸出“b=10”說明程序并沒有認為doSomething()方法拋出了異常,為什么呢?
根據(jù)Java語言規(guī)范文檔14.20.2,
- If the catch block completes abruptly for reason R, then the finally block is executed.
- If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and reason R is discarded).
翻譯:
在一個try-catch-finally語句中,如果catch語句塊由于原因R立即結(jié)束,例如return或者出現(xiàn)異常,那么會繼續(xù)執(zhí)行finally語句塊。
當finally語句塊由于原因S立即結(jié)束,例如使用了return語句或者出現(xiàn)異常,那么try語句也會由于原因S立即結(jié)束,并且之前造成catch語句塊立即結(jié)束的原因R(出現(xiàn)異常)會被丟棄。
在JVM層面,根據(jù)JVM文檔3.13. Compiling finally,
If a new value is thrown during execution of the finally clause, the finally clause aborts, and tryCatchFinally returns abruptly, throwing the new value to its invoker.
翻譯:
如果finally子句在執(zhí)行期間拋出一個新值,finally子句中止,整個try-catch-finally語句塊立即返回,將這個新值拋給上層調(diào)用者。
總結(jié)
在try-catch-finally語句塊中,finally語句塊中的return/拋出異常(立即結(jié)束語句)的優(yōu)先級最高,程序會優(yōu)先返回finally語句塊中的立即結(jié)束語句的結(jié)果,此時try-catch語句塊中的return/拋出異常(立即結(jié)束語句)的結(jié)果就會被丟棄掉。
所以我們在將捕獲的異常拋出給調(diào)用的上層方法處理時,如果被finally語句塊中的return語句覆蓋掉了,那么這個導致異常的錯誤情況將很難發(fā)現(xiàn)和定位。
廣告
【火線解碼】系列文章由專注于安卓代碼掃描的火線產(chǎn)品團隊提供,火線官網(wǎng):http://magic.#
—— 用火線,守住代碼底線!