Java中assert關鍵字的實現

Javaassert關鍵字的實現

 

J2SE 1.4在語言上提供了一個新特性,就是assertion(斷言)功能,它是該版本在Java語言方面最大的革新。在軟件開發中,assertion是一種經典的調試、測試方式。

assertion(斷言)在軟件開發中是一種常用的調試方式,很多開發語言中都支持這種機制,如CC++Eiffel等,但是支持的形式不盡相同,有的是通過語言本身、有的是通過庫函數等。另外,從理論上來說,通過assertion方式可以證明程序的正確性,但是這是一項相當複雜的工作,目前還沒有太多的實踐意義。

  在實現中,assertion就是在程序中的一條語句,它對一個boolean表達式進行檢查,一個正確程序必須保證這個boolean表達式的值爲true;如果該值爲false,說明程序已經處於不正確的狀態下,系統將給出警告或退出。一般來說,assertion用於保證程序最基本、關鍵的正確性。assertion檢查通常在開發和測試時開啓。爲了提高性能,在軟件發佈後,assertion檢查通常是關閉的。下面簡單介紹一下Javaassertion的實現。

  1.1) 語法表示

  在語法上,爲了支持assertionJava增加了一個關鍵字assert。它包括兩種表達式,分別如下:

  assert expression1;

  assert expression1: expression2;

  在兩種表達式中,expression1表示一個boolean表達式,expression2表示一個基本類型或者是一個對象(Object) ,基本類型包括boolean,char,double,float,intlong。由於所有類都爲Object的子類,因此這個參數可以用於所有對象。

  1assert

  如果爲true,則程序繼續執行。

  如果爲false,則程序拋出AssertionError,並終止執行。

  2assert : <錯誤信息表達式>

  如果爲true,則程序繼續執行。

  如果爲false,則程序拋出java.lang.AssertionError,並輸出<錯誤信息表達式>

  1.2) 語義含義

  在運行時,如果關閉了assertion功能,這些語句將不起任何作用。如果打開了assertion功能,那麼expression1的值將被計算,如果它的值爲false,該語句強拋出一個AssertionError對象。如果assertion語句包括expression2參數,程序將計算出expression2的結果,然後將這個結果作爲AssertionError的構造函數的參數,來創建AssertionError對象,並拋出該對象;如果expression1值爲trueexpression2將不被計算。

  一種特殊情況是,如果在計算表達式時,表達式本身拋出Exception,那麼assert將停止運行,而拋出這個Exception

  1.3) 一些assertion例子

  下面是一些Assert的例子。

  assert  0 < value;

  assert  0 < value:"value="+value;

  assert  ref != null:"ref doesn''t equal null";

  assert  isBalanced();

  1.4) 編譯

  由於assert是一個新關鍵字,使用老版本的JDK是無法編譯帶有assert的源程序。因此,我們必須使用JDK1.4(或者更新)Java編譯器,在使用Javac命令時,我們必須加上-source 1.4作爲參數。-source 1.4表示使用JDK 1.4版本的方式來編譯源代碼,否則編譯就不能通過,因爲缺省的Javac編譯器使用JDK1.3的語法規則。

  一個簡單的例子如下:

  javac -source 1.4 test.java

  1.5) 運行

  由於帶有assert語句的程序運行時,使用了新的ClassLoaderClass類,因此,這種程序必須在JDK1.4(或者更高版本)JRE下運行,而不能在老版本的JRE下運行。

  由於我們可以選擇開啓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 打開MyClass1assertion

  -da: java -da: MyClass1 關閉MyClass1assertion

  -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

      1.6)說明

       assertion爲開發人員提供了一種靈活地調試和測試機制,它的使用也非常簡單、方便。


   
設置執行參數:
   
 

 

   
即可。 
  

 

斷言概述


  
編寫代碼時,我們總是會做出一些假設,斷言就是用於在代碼中捕捉這些假設
  
可以將斷言看作是異常處理的一種高級形式
  
斷言表示爲一些布爾表達式,程序員相信在程序中的某個特定點該表達式值爲真
  
可以在任何時候啓用和禁用斷言驗證,因此可以在測試時啓用斷言而在部署時禁用斷言。同樣,程序投入運行後,最終用戶在遇到問題時可以重新起用斷言。
  
使用斷言可以創建更穩定,品質更好且易於除錯的代碼
  
當需要在一個值爲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 shoule be enable!");
     }
   }
}


何時需要使用斷言


  1.
可以在預計正常情況下程序不會到達的地方放置斷言 assert false
  2.
斷言可以用於檢查傳遞給私有方法的參數。(對於公有方法,因爲是提供給外部的接口,所以必須在方法中有相應的參數檢驗才能保證代碼的健壯性)
  3.
使用斷言測試方法執行的前置條件和後置條件
  4.
使用斷言檢查類的不變狀態,確保任何情況下,某個變量的狀態必須滿足。(如age屬性應大於0小於某個合適值)


什麼地方不要使用斷言


  
斷言語句不是永遠會執行,可以屏蔽也可以啓用
因此:
  1.
不要使用斷言作爲公共方法的參數檢查,公共方法的參數永遠都要執行

(很多文章都是這麼說的,但是不是很明白,看了下官方文檔)

Do not use assertions for argument checking in public methods.

Argument checking is typically part of the published specifications (or contract) of a method, and these specifications must be obeyed whether assertions are enabled or disabled. Another problem with using assertions for argument checking is that erroneous arguments should result in an appropriate runtime exception (such as IllegalArgumentException, IndexOutOfBoundsException, or NullPointerException). An assertion failure will not throw an appropriate exception.

也就是就是公共方法它的參數檢測不應該和assertions啓用和關閉有關。如果你的測試失敗了,assertions所拋出的異常其實不是一個真正你參數測試失敗的異常!
  2.
斷言語句不可以有任何邊界效應,不要使用斷言語句去修改變量和改變方法的返回值

參考:
http://java.sun.com/j2se/1.4.2/docs/guide/lang/assert.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章