我在前面的「Shit? Happens」一文中提到一個名為 Shit? 的 RuntimeException,我用它來幫助找出自己因疏忽而造成的程序錯誤,但是這種方式畢竟有點(diǎn)麻煩,而且有一些伴隨而來的問題。使用 Shit? Exception 的缺點(diǎn)包括了:
-
程序員要自行產(chǎn)生并丟出一個
Shit?
對象。
?
-
發(fā)生這種問題時,通常是很嚴(yán)重的狀況,不應(yīng)該是
Runtime Exception
,應(yīng)該是
Error
比較恰當(dāng)。
-
?
產(chǎn)品交付給客戶之前,程序員必須手動將程序代碼中所有的這些檢查都刪除,否則對于執(zhí)行效率會有不好的影響。
Java? 2 SDK 1.4 新增的 assertion 功能,和 Shit? Exception 的目的一樣,但可以免去 Shit? Exception 的這些缺點(diǎn)。所以我已經(jīng)開始改用 assertion,而不再使用 Shit? Exception 了。
你可以在 Java? 程序 method 內(nèi)的任何地方插入 assertion 敘述來做檢查。Assertion 敘述(statement)的方法是在 assert 這個關(guān)鍵詞(keyword)之后加上一個布爾(boolean)判斷式,然后以分號結(jié)束此敘述。如下例所示:
assert size() == 0;
程序中如果使用到 assertion,編譯時必須加上「-source 1.4」的選項(xiàng)來告訴 javac 編譯器,否則 javac 預(yù)設(shè)的狀況是不支持 assertion 語法的。執(zhí)行的時候必須以「-ea」的選項(xiàng)設(shè)定來告訴 JRE 必須執(zhí)行 assertion,當(dāng)程序執(zhí)行到 assertion 敘述時,如果布爾判斷式不成立,系統(tǒng)會丟出 AssertionError 的錯誤對象。如果不用「-ea」選項(xiàng),執(zhí)行時會忽略 assertion 敘述不予執(zhí)行。
Assertion 看起來很神奇,其實(shí)骨子里很平庸。透過編譯器和 class loader 的合作就可以達(dá)到 assertion 的支持,根本不需要 JVM 在指令集(instruction set)中新增 opcode。舉例來說,「assert size() == 0;」這道敘述會被編譯器當(dāng)成下面的程序代碼來編譯:
if (ea) {
?? if( size() != 0 ) {
???? throw new AssertionError();
?? }
}
編譯器并會在此 class 的 bytecode 中插入一個類似下面的私用靜態(tài)合成字段(private static synthetic field):?
private static boolean ea = false;
因?yàn)?span lang="EN-US"> ea(意思是 enable assertion)的默認(rèn)值是 false,所以預(yù)設(shè)情況下是不會執(zhí)行 assertion 的。如果你透過「-ea」選項(xiàng)來執(zhí)行,那么 class loader 會在加載此 class 的時候,將 ea 設(shè)為 true,所以就能執(zhí)行 assertion。
執(zhí)行程序時,如果把 assertion 功能打開,會造成執(zhí)行時效率稍微變差,而且不管有沒有透過「-ea」來把 assertion 功能打開,assertion 的程序代碼都會一直存在 bytecode 中,會造成體積的增大,這兩點(diǎn)是使用 assertion 要付出的代價,所以在程序中使用 assertion 的時機(jī),仍須仔細(xì)斟酌。只要使用得宜,assertion 可以是程序員很好的除錯幫手。
商標(biāo)聲名:
Java? is a trademark of Sun Microsystems.
Shit? is a trademark of Jerry Tsai.
?