編程斷言
編寫代碼時,我們總是會做出一些假設,斷言就是用於在代碼中捕捉這些假設。斷言表示為一些布爾表達式,程式設計師相信在程式中的某個特定點該表達式值為真,可以在任何時候啟用和禁用斷言驗證,因此可以在測試時啟用斷言而在部署時禁用斷言。同樣,程式投入運行後,最終用戶在遇到問題時可以重新啟用斷言。
使用斷言可以創建更穩定、品質更好且 不易於出錯的代碼。當需要在一個值為FALSE時中斷當前操作的話,可以使用斷言。單元測試必須使用斷言(Junit/JunitX)。
除了類型檢查和單元測試外,斷言還提供了一種確定各種特性是否在程式中得到維護的極好的方法。
使用斷言使我們向按契約式設計更近了一步。
斷言方式
斷言可以有兩種形式
1.assert Expression1
2.assert Expression1:Expression2
其中Expression1應該總是一個布爾值,Expression2是斷言失敗時輸出的失敗訊息的字元串。如果Expression1為假,則拋出一個 AssertionError,這是一個錯誤,而不是一個異常,也就是說是一個不可控制異常(unchecked Exception),AssertionError由於是錯誤,所以可以不捕獲,但不推薦這樣做,因為那樣會使你的系統進入不穩定狀態。
啟用斷言
斷言在默認情況下是關閉的,要在編譯時啟用斷言,需要使用source1.4標記 既javac source1.4 Test.java ,在運行時啟用斷言需要使用 -ea參數 。要在系統類中啟用和禁用斷言可以使用 -esa 和 -dsa參數。
例如:
public class AssertExampleOne{
public AssertExampleOne(){}
public static void main(String args[]){
int x=10;
System.out.println("Testing Assertion that x==100");
assert x==100:"Out assertion failed!";
System.out.println("Test passed!");
}
}
如果編譯時未加 -source1.4,則編譯通不過
在執行時未加 -ea 時輸出為
Testing Assertion that x==100
Test passed
jre忽略了斷言的舊代碼,而使用了該參數就會輸出為
Testing Assertion that x==100
Exception in thread "main" java.lang.AssertionError: Out assertion failed!
at AssertExampleOne.main(AssertExampleOne.java:6)
副作用
由於程式設計師的問題,斷言的使用可能會帶來副作用 ,例如:
boolean isEnable=false;
//...
assert isEnable=true;
這個斷言的副作用是因為它修改了程式中變數的值並且未拋出錯誤,這樣的錯誤如果不細心的檢查是很難發現的。但是同時我們可以根據以上的副作用得到一個有用的特性,根據它來測試斷言是否打開。
public class AssertExampleTwo{
public static void main(String args[]){
boolean isEnable=false;
//...
assert isEnable=true;
if(isEnable==false){
throw new RuntimeException("Assertion should be enabled!");
}
}
}
不要使用
斷言語句不是永遠會執行,可以禁止也可以啟用
因此:
1.不要使用斷言作為公共方法的參數檢查,公共方法的參數永遠都要執行
2.斷言語句不可以有任何邊界效應,不要使用斷言語句去修改變數和改變方法的返回值
下邊是介紹斷言的用法:
assert是在J2SE1.4中引入的新特性,assertion就是在代碼中包括的布爾型狀態,程式設計師認為這個狀態是true。一般來說assert在開發的時候是檢查程式的安全性的,在發布的時候通常都不使用assert。在1.4中添加了assert關鍵字和java.lang.AssertError類的支持。
首先,我們有必要從一個例子說起assert
public class AssertTest
{
public static void main(String[] args)
{
AssertTest at = new AssertTest();
at.assertMe(true);
at.assertMe(false);
}
private void assertMe(boolean boo)
{
assert boo?true:false;
System.out.println("true condition");
}
}
程式中包含了assert的話,你要用javac -source 1.4 xxx.java來編譯,否則編譯器會報錯的。要想讓assert得部分運行的話,要使用java -ea xxx來運行,否則包含assert得行會被忽略。下面我們運行
javac -source 1.4 AssertTest.java
java -ea AssertTest
看看結果的輸出是:
true condition
Exception in thread "main" java.lang.AssertionError
at AssertTest.assertMe(AssertTest.java:13)
at AssertTest.main(AssertTest.java:7)
當我們運行at.assertMe(true)得時候,由於assert boo?true:false相當於 assert true;因此沒有任何問題,程式往下執行列印出true condition,但是執行at.assertMe(false)的時候相當於assert false,這個時候解釋器就會拋出AssertionError了,程式就終止了。大家必須清楚AssertionError是繼承自Error得,因此你可以不再程式中catch它的,當然你也可以在程式中catch它然後程式可以繼續執行。例如:
public class AssertTest
{
public static void main(String[] args)
{
AssertTest at = new AssertTest();
try
{
at.assertMe(true);
at.assertMe(false);
}
catch(AssertionError ae)
{
System.out.println("AsseriontError catched");
}
System.out.println("go on");
}
private void assertMe(boolean boo)
{
assert boo?true:false;
System.out.println("true condition");
}
}
assert還有另外一種表達的方式,就是assert exp1:exp2;其中exp1是個boolean返回值得表達式,而exp2可以是原始的數據類型或者對象都可以例如:
boolean boo = true;
String str = null;
assert boo = false:str="error";
我們剛開始講得assert exp1得形式,當exp1是false得時候,AssertionError得默認構造器會被調用,但是assert exp1:exp2這樣的形式,當exp1為true的時候後面exp2被或略,如果false的話,後面的表達式的結果會被計算出來並作為AssertionError得構造器參數。看下面的例子:
public class AssertTest
{
public static void main(String[] args)
{
AssertTest at = new AssertTest();
at.assertMe(true);
at.assertMe(false);
}
private void assertMe(boolean boo)
{
String s = null;
assert boo?true:false:s = "hello world";
System.out.println("true condition");
}
}運行的時候會得到這樣的結果
true condition
Exception in thread "main" java.lang.AssertionError: hello world
at AssertTest.assertMe(AssertTest.java:14)
at AssertTest.main(AssertTest.java:7)
Assert最好不要濫用,原因是assert並不一定都是enable的,下面兩種情況就不應該用assert
不要再public的方法裡面檢查參數是不是為null之類的操作
例如public int get(String s)
{
assert s != null;
}
如果需要檢查也最好通過if s = null 拋出NullPointerException來檢查
不要用assert來檢查方法操作的返回值來判斷方法操作的結果
例如 assert list.removeAll();這樣看起來好像沒有問題 但是想想如果assert 被disable呢,那樣他就不會被執行了 所以removeAll()操作就沒有被執行 可以這樣代替
boolean boo = list.removeAl();
assert boo;
就說這么多吧,assert是scjp1.4的考試內容 所以還是有必要了解的
使用斷言
1.可以在預計正常情況下程式不會到達的地方放置斷言 :assert false
2.斷言可以用於檢查傳遞給私有方法的參數。(對於公有方法,因為是提供給外部的接口,所以必須在方法中有相應的參數檢驗才能保證代碼的健壯性)
3.使用斷言測試方法執行的前置條件和後置條件
4.使用斷言檢查類的不變狀態,確保任何情況下,某個變數的狀態必須滿足。(如age屬性應大於0小於某個合適值)