java assert [轉]

1、assertion的意義和用法
J2SE 1.4在語言上提供了一個新特性,就是assertion功能,它是該版本在Java語言方面最大的革新。
從理論上來講,經過 assertion方式能夠證實程序的正確性,可是這是一項至關複雜的工做,目前尚未太多的實踐意義。
在實現中,assertion就是在程序中的一條語句,它對一個boolean表達式進行檢查,一個正確程序必須保證這個boolean表達式的值爲true;若是該值爲false,說明程序已經處於不正確的狀態下, 系統將給出警告或退出
通常來講,assertion用於保證程序最基本、關鍵的正確性。assertion檢查一般在開發和測試時開啓。爲了提升性能,在軟件發佈後,assertion檢查一般是關閉的。
一、語法表示
在語法上,爲了支持assertion,Java增長了一個關鍵字assert。它包括兩種表達式,分別以下:
        assert  expression1;
        assert  expression1:expression2;
在兩種表達式中,expression1表示一個boolean表達式, expression2表示一個基本類型或者是一個對象(Object),基本類型包括boolean,char,double,float,int和 long。因爲全部類都爲Object的子類,所以這個參數能夠用於全部對象。
二、含義
在運行時,若是關閉了assertion功能,這些語句將不起任何做用。若是打開了assertion功能,那麼expression1的值將被計算,若是它的值爲false,該語句強拋出一個AssertionError對象。
若是assertion語句包括expression2參數,程序將計算出 expression2的結果,而後將這個結果做爲AssertionError的構造函數的參數,來建立AssertionError對象,並拋出該對 象;若是expression1值爲true,expression2將不被計算。
一種特殊狀況是,若是在計算表達式時,表達式自己拋出Exception,那麼assert將中止運行,而拋出這個Exception。
三、編譯
因爲assert是一個新關鍵字,使用老版本的JDK是沒法編譯帶有assert的 源程序。所以,咱們必須使用JDK1.4(或者更新)的Java編譯器,在使用Javac命令時,咱們必須加上-source 1.4做爲參數。-source 1.4表示使用JDK 1.4版本的方式來編譯源代碼,不然編譯就不能經過,由於缺省的Javac編譯器使用JDK1.3的語法規則。
你們在使用eclipse,jbuilder等IDE工具的時候,要注意編譯器的版本,使用的jre,不等因而javac 的版本
一個簡單的例子以下: javac -source 1.4 AssertTest.java 
四、運行
因爲咱們能夠選擇開啓assertion功能,或者不開啓,另外咱們還能夠開啓一部 分類或包的assertion功能。經過這些選項,咱們能夠過濾全部咱們不關心的類,只選擇咱們關心的類或包來觀察。
          參數 -esa 和 -dsa
它們含義爲開啓(關閉) 系統類的assertion功能。因爲新版本的Java的系統類中,也使了assertion語句,所以若是用戶須要觀察它們的運行狀況,就須要打開系統類的assertion功能 ,咱們可以使用-esa參數打開,使用 -dsa參數關閉。
-esa和-dsa的全名爲-enablesystemassertions和-disenablesystemassertions,全名和縮寫名有一樣的功能。
參數 -ea和-ea
它們含義爲開啓(關閉) 用戶類的assertion功能:經過這個參數,用戶能夠打 開某些類或包的assertion功能,一樣用戶也能夠關閉某些類和包的assertion功能。打開assertion功能參數爲-ea;若是不帶任何 參數,表示打開全部用戶類;若是帶有包名稱或者類名稱,表示打開這些類或包;若是包名稱後面跟有三個點,表明這個包及其子包;若是隻有三個點,表明無名 包。關閉assertion功能參數爲-da,使用方法與-ea相似。
-ea和-da的全名爲-enableassertions和-disenableassertions,全名和縮寫名有一樣的功能。下面表示了參數及其含義。
參數 例子 說明
-ea java -ea 打開全部用戶類的assertion
-da java -da 關閉全部用戶類的assertion
-ea: java -ea:MyClass1 打開MyClass1的assertion
-da: java -da: MyClass1 關閉MyClass1的assertion
-ea: java -ea:pkg1 打開pkg1包的assertion
-da: java -da:pkg1 關閉pkg1包的assertion
-ea:... java -ea:... 打開缺省包(無名包)的assertion
-da:... java -da:... 關閉缺省包(無名包)的assertion
-ea:... java -ea:pkg1... 打開pkg1包和其子包的assertion
-da:... java -da:pkg1... 關閉pkg1包和其子包的assertion
-esa java -esa 打開系統類的assertion
-dsa java -dsa 關閉系統類的assertion
綜合使用 java -dsa:MyClass1:pkg1 關閉MyClass1和pkg1包的assertion
其中...表明,此包和其子包的含義。例如咱們有兩個包爲pkg1和pkg1.subpkg。
那麼pkg1...就表明pkg1和pkg1.subpkg兩個包。
另外,Java爲了讓程序也可以動態開啓和關閉某些類和包的assertion功能,Java修該了Class和ClassLoader的實現,增長了幾個用於操做assert的API。下面簡單說明一下幾個API的做用。
ClassLoader類中的幾個相關的API:
setDefaultAssertionStatus:
用於開啓/關閉assertion功能
setPackageAssertionStatus:
用於開啓/關閉某些包的assertion功能
setClassAssertionStatus:
用於開啓/關閉某些類的assertion功能
clearAssertionStatus:
用於關閉assertion功能
2、assertion的設計問題
首先,咱們認爲assertion是必要的。由於,若是沒有統一的assertion機制,Java程序一般使用if-then-else或者switch-case語句進行assertion檢查,並且檢查的數據類型也不徹底相同。
assertion機制讓Java程序員用統一的方式處理assertion問題, 而不是按本身的方式處理。另外,若是用戶使用本身的方式進行檢查,那麼這些代碼在發佈之後仍然將起做用,這可能會影響程序的性能。而從語言言層次支持 assertion功能,這將把assertion對性能帶來的負面影響降到最小。
Java是經過加強一個關鍵字assert實現支持assertion,而不是 使用一個庫函數支持,這說明Java認爲assertion對於語言自己來講是很是重要的。C語言就是 經過Assert.h函數庫實現斷言的支持。
Java的assertion的開啓也和C語言不太同樣,咱們都知道在C語言中,assertion的開啓是在編譯時候決定的。當咱們使用debug方式編譯程序時候,assertion被開啓,而使用release方式編譯時候,assertion自動被關閉。
Java的assertion倒是在運行的時候進行決定的。其實,這兩種方式是各有優缺點。若是採用編譯時決定方式,開發人員將處理兩種類型的目標碼,debug版本和release版本,這加大了文檔管理的難度,可是提升了代碼的運行效率。
Java採用運行時決定的方式,這樣全部的assertion信息將置於目標代碼 中,同一目標代碼能夠選擇不一樣方式運行,加強目標代碼的靈活性,可是它將犧牲由於assertion而引發一部分性能損失。
另外,咱們注意到AssertionError做爲Error的一個子類,而不 是RuntimeException。Error表明一些異常的錯誤,一般是不能夠恢復的,而 RuntimeException強調該錯誤在運行時才發生的特色。AssertionError一般爲很是關鍵的錯誤,這些錯誤每每是不容易恢復的,並且assertion機制也不鼓勵程序員對這種錯誤進行恢復。
3、assertion與繼承
若是一個assert語句在父類,而當它的子類調用它時,該assert爲false。 父類的assert語句將只有在父類的assert開啓才起做用,若是僅僅開啓子類的assert,父類的assert仍然不運行。 所以,assert語句不具備繼承功能。
4、assertion的使用
assertion的使用是一個複雜的問題,一般來講, assertion用於檢查一些關鍵的值,而且這些值對整個程序,或者局部功能的完成有很大的影響,而且這種錯誤不容易恢復的。
assertion表達式應該短小、易懂,若是須要評估複雜的表達式,應該使用函數計算。如下是一些使用assertion的狀況的例子,這些方式可讓java程序的可靠性更高。
檢查控制流; 在if-then-else和swith-case語句中,咱們能夠在不該該發生的控制支流上加上assert false語句。若是這種狀況發生了,assert可以檢查出來。
在私有函數計算前,檢查輸入參數是否有效;對於一私有些函數,要求輸入知足一些特定的條件,那麼咱們能夠在函數開始處使用assert進行參數檢查。
對於公共函數,咱們一般不使用assertion檢查,由於通常來講,公共函數必須對無效的參數進行檢查和處理。而私有函數每每是直接使用的。例如:某函數可能要求輸入的參數必須不爲null。那麼咱們能夠在函數的一開始加上:
assert parameter1!=null : 
"paramerter is null in test method";
在函數計算後,檢查函數結果是否有效;對於一些計算函數,函數運行完成後,某些值須要保證必定的性質,所以咱們能夠經過assert檢查該值。例如,咱們有一個計算絕對值的函數,那麼咱們就能夠在函數的結果處,加上一個語句:
assert  value>=0:
"Value should be bigger than 0:"+value;
經過這種方式,咱們能夠對函數計算完的結果進行檢查。檢查程序不變量;有些程序中,存在一些不變量,在程序的運行生命週期,這些不變量的值都是不變的。這些不變量多是一個簡單表達式,也多是一個複雜的表達式。
對於一些 關鍵的不變量,咱們能夠經過assert進行檢查。例如,在一個財會系統中,公司的支出和收入必須保持必定的平衡關係,所以咱們能夠編寫一個表達式檢查這種平衡關係,以下表示:
private boolean isBalance() 
{ 
           …… 
         }
在這個系統中,在一些可能影響這種平衡關係的方法的先後,咱們均可以加上assert驗證:
assert isBalance():"balance is destoried";
5、補充
必須清楚AssertionError是繼承自Error得,所以你能夠再也不程序中catch它的,固然你也能夠在程序中catch它而後程序能夠繼續執行。
  1. 不要再public的方法裏面檢查參數是否是爲null之類的操做
    例如public int get(String s)
       {
           assert s != null;
       }
    若是須要檢查也最好經過if s = null 拋出NullPointerException來檢查
  2. 不要用assert來檢查方法操做的返回值來判斷方法操做的結果    例如 assert list.removeAll();這樣看起來好像沒有問題 可是想一想若是assert 被disable呢,那樣他就不會被執行了 因此removeAll()操做就沒有被執行  能夠這樣代替 boolean boo = list.removeAl(); assert boo;
相關文章
相關標籤/搜索