在本教程中,我們將借助示例學(xué)習(xí)Java assert語句(Java斷言)。
Java中的斷言通過測試我們認(rèn)為是正確的代碼來幫助檢測錯誤。
使用assert關(guān)鍵字進(jìn)行斷言。
其語法為:
assert condition;
這里condition是一個布爾表達(dá)式,我們假定在程序執(zhí)行時為真。
默認(rèn)情況下,斷言在運(yùn)行時被禁用并被忽略。
為了啟用斷言,我們使用:
java -ea:arguments
或者
java -enableassertions:arguments
啟用斷言且條件為時true,程序?qū)⒄?zhí)行。
但是,如果在啟用斷言時條件計(jì)算為false, JVM會拋出AssertionError,程序會立即停止。
class Main { public static void main(String args[]) { String[] weekends = {"Friday", "Saturday", "Sunday"}; assert weekends.length == 2; System.out.println("這個星期有 " + weekends.length + " 個周末"); } }
輸出結(jié)果
這個星期有 3 個周末
我們得到上面的輸出,因?yàn)樵摮绦驔]有編譯錯誤,并且默認(rèn)情況下,斷言被禁用。
啟用斷言后,我們得到以下輸出:
Exception in thread "main" java.lang.AssertionError
assert condition : expression;
在這種形式的斷言語句中,將表達(dá)式傳遞到AssertionError對象的構(gòu)造函數(shù)。 如果條件為false,則該表達(dá)式的值顯示為錯誤的詳細(xì)信息。
詳細(xì)消息用于捕獲和傳輸斷言失敗的信息,以幫助調(diào)試問題。
class Main { public static void main(String args[]) { String[] weekends = {"Friday", "Saturday", "Sunday"}; assert weekends.length==2 : "There are only 2 weekends in a week"; System.out.println("There are " + weekends.length + " weekends in a week"); } }
輸出結(jié)果
Exception in thread "main" java.lang.AssertionError: There are only 2 weekends in a week
從上面的示例可以看出,表達(dá)式被傳遞給AssertionError對象的構(gòu)造函數(shù)。如果我們的假設(shè)是正確的false,并且啟用了斷言,則會拋出異常并顯示一條適當(dāng)?shù)南ⅰ?/p>
此消息有助于診斷和修復(fù)導(dǎo)致斷言失敗的錯誤。
如果我們不向斷言命令行開關(guān)提供任何參數(shù),
java -ea
這將在除系統(tǒng)類之外的所有類中啟用斷言。
我們還可以使用參數(shù)為特定的類和包啟用斷言。 可以提供給這些命令行開關(guān)的參數(shù)為:
在類名中啟用斷言
為了對程序Main的所有類啟用斷言,
java -ea Main
只啟用一個類,
java -ea:AnimalClass Main
這只允許在Main程序的AnimalClass中使用斷言。
在包名稱中啟用斷言
要對包c(diǎn)om.animal及其子包啟用斷言
java -ea:com.animal... Main
在未命名的包中啟用斷言
在當(dāng)前工作目錄中的未命名包中啟用斷言(當(dāng)我們不使用package語句時)。
java -ea:... Main
在系統(tǒng)類中啟用斷言
為了在系統(tǒng)類中啟用斷言,我們使用不同的命令行開關(guān):
java -esa:arguments
或
java -enablesystemassertions:arguments
可以提供給這些開關(guān)的參數(shù)是相同的。
要禁用斷言,我們使用:
java -da arguments
或
java -disableassertions arguments
要在系統(tǒng)類中禁用斷言,我們使用:
java -dsa:arguments
或
java -disablesystemassertions:arguments
禁用斷言時可以傳遞的參數(shù)與啟用斷言時相同。
快速高效地檢測和糾正錯誤。
斷言檢查僅在開發(fā)和測試期間進(jìn)行。它們會在運(yùn)行時自動在生產(chǎn)代碼中刪除,因此不會減慢程序的執(zhí)行速度。
它有助于刪除樣板代碼并使代碼更具可讀性。
重構(gòu)和優(yōu)化代碼,以增強(qiáng)其正確運(yùn)行的信心。
無法訪問的代碼是我們嘗試運(yùn)行該程序時不會執(zhí)行的代碼。使用斷言來確保無法訪問的代碼實(shí)際上是無法訪問的。
讓我們舉個實(shí)例。
void unreachableCodeMethod() { System.out.println("Reachable code"); return; // Unreachable code System.out.println("Unreachable code"); assert false; }
讓我們再來看一個沒有默認(rèn)情況的switch語句示例。
switch (dayOfWeek) { case "Sunday": System.out.println("It’s Sunday!"); break; case "Monday": System.out.println("It’s Monday!"); break; case "Tuesday": System.out.println("It’s Tuesday!"); break; case "Wednesday": System.out.println("It’s Wednesday!"); break; case "Thursday": System.out.println("It’s Thursday!"); break; case "Friday": System.out.println("It’s Friday!"); break; case "Saturday": System.out.println("It’s Saturday!"); break; }
上面的switch語句表明,一周中的天數(shù)只能是以上7個值中的一個。沒有默認(rèn)情況意味著程序員相信這些情況中的一個將始終被執(zhí)行。
但是,在某些假設(shè)實(shí)際上是錯誤的情況下,可能尚未考慮某些情況。
應(yīng)該使用斷言來檢查此假設(shè),以確保未達(dá)到默認(rèn)switch條件。
default: assert false: dayofWeek + " is invalid day";
如果dayOfWeek其值不是有效日期,則拋出AssertionError。
為了記錄其基本假設(shè),許多程序員使用注釋。讓我們舉個實(shí)例。
if (i % 2 == 0) { ... } else { // We know (i % 2 == 1) ... }
請改用斷言。
隨著程序的增長,注釋可能會過時和不同步。 但是,我們將不得不更新assert語句; 否則,它們也可能因有效條件而失敗。
if (i % 2 == 0) { ... } else { assert i % 2 == 1 : i; ... }
用戶可以提供公共方法中的參數(shù)。
因此,如果使用斷言來檢查這些參數(shù),則條件可能會失敗并導(dǎo)致AssertionError。
與其使用斷言,不如讓它產(chǎn)生適當(dāng)?shù)倪\(yùn)行時異常并處理這些異常。
不要調(diào)用方法或評估可能在斷言條件下影響程序操作的異常。
讓我們以一個列表示例為例,weekdays列表包含一周中所有天的名稱。
ArrayList<String> weekdays = new ArrayList<>(Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" )); ArrayList<String> weekends= new ArrayList<>(Arrays.asList("Sunday", "Saturday" )); assert weekdays.removeAll(weekends);
在這里,我們試圖從ArrayList weekdays中刪除元素Saturday和Sunday。
如果啟用了斷言,則程序可以正常運(yùn)行。但是,如果禁用了斷言,則不會刪除列表中的元素。這可能會導(dǎo)致程序失敗。
而是將結(jié)果分配給變量,然后使用該變量進(jìn)行斷言。
ArrayList<String> weekdays = new ArrayList<>(Arrays.asList("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" )); ArrayList<String> weekends= new ArrayList<>(Arrays.asList("Sunday", "Saturday" )); boolean weekendsRemoved = weekdays.removeAll(weekends); assert weekendsRemoved;
這樣,我們可以確保從weekdays中刪除所有weekends,而不考慮啟用或禁用斷言。 結(jié)果,它不會影響將來的程序操作。