Java SE 6 技術手冊

10.5 斷言(Assertion)

例外是程式中非預期的錯誤,例外處理是在這些錯誤發生時所採取的措施。 有些時候,您預期程式中應該會處於何種狀態,例如某些情況下某個值必然是多少,這稱之為一種斷言。斷言有兩種結果:成立或不成立。當預期結果與實際執行相同時,斷言成立,否則斷言不成立。

Java 在 JDK 1.4 之後提供斷言陳述,有兩種使用的語法:

assert boolean_expression;
assert boolean_expression : detail_expression;

boolean_expression 如果為 true,則什麼事都不會發生,如果為 false,則會發生 java.lang.AssertionError,此時若採取的是第二個語法,則會將 detail_expression 的結果顯示出來,如果當中是個物件,則呼叫它的 toString() 顯示文字描述結果。

一個使用斷言的時機是內部不變量(Internal invarant)的判斷,例如在某個時間點上,或某個狀況發生時,您判斷某個變數必然要是某個值,舉個例子來說:

範例 10.9 AssertionDemo.java

public class AssertionDemo {
    public static void main(String[] args) {
        if(args.length > 0) {
            System.out.println(args[0]);
        }
        else {
            assert args.length == 0;
            System.out.println("沒有輸入引數");
        }
    }
}

在正常的預期中,陣列長度是不會小於 0 的,所以一但執行至 else 區塊,陣列長度必然只有一個可能,就是等於 0,您斷言 args.length==0 結果 必然成立,else 之中的程式碼也只有在斷言成立的狀況下才能執行,如果不成立,表示程式運行存在錯誤,else 區塊不應被執行,您要停下來檢查程式的錯誤,事實上斷言主要的目的通常是在開發時期測試使用。

斷言功能是在 JDK 1.4 之後提供的,由於斷言使用 assert 作為關鍵字,為了避免您以前在 JDK 1.3 或更早之前版本的程式使用了 assert 作為變數,而導致的名稱衝突問題,預設上執行時是不啟動斷言檢查的,如果您要在執行時啟動斷言檢查,可以使用 -enableassertions 或是 -ea 引數,例如:

java –ea AssertionDemo

另一個使用斷言的時機為控制流程不變量(Control flow invariant)的判斷,例如在使用 switch 時:

switch(var) {
    case Constants.Con1:
        ...
        break;
    case Constants.Con2:
        ...
        break;
    case Constants.Con3:
        ...
        break;
    default:
        assert false : "非定義的常數";
}

假設您已經在 switch 中列出了所有的常數,即 var 不該出現 Constants.Con1、Constants.Con2、 Constants.Con3 以外的常數,則如果發生 default 被執行的情況,表示程式的狀態與預期不符,此時由於 assert false,所以必然斷言失敗。

簡單的說,斷言是判定程式中的某個執行點必然是某個狀態,所以它不能當作像 if 之類的判斷式來使用,Assertion 不應被當做程式執行流程的一部份。