用assertions使你的代碼更加穩定
瞭解Java的assertions(斷言)效能是怎樣為開發人員提供更好的方法來建立穩定的、高品質的、易調試的代碼的。
by Josh Street
或許你還沒有注意到,Sun Microsystems已經將一個新的關鍵字添加到Java語言中去了。這個assert關鍵字是由JSR41 -- 一個最終將真正的assertions效能添加到Java中去的Java Specification Request提出的。由於這個新的assert關鍵字和大多數C/C++開發人員所熟悉的用法有很大的區別,因此詳細地瞭解它一定會使你有所受益。
Java的assertions特性用於一個特殊的目的:當使用者定義的布林運算式為False時它會拋出一個錯誤。更確切地說,一個assertion被當作一個發現某個值變成false的訊號,它用來指示當前函數需要被中斷。該效能被用在建立不該出現在真正產品部署過程中的專用偵錯模式上時非常有用。
開啟 Assertion
在使用assertions之前,你需要開啟(enable)它們,因為Java Runtime Environment (JRE)會自動將所有的assertions關閉。你可以用–enableassertions 標記(flag)(縮寫是–ea)來開啟它;同樣,用–disableassertions 標記(縮寫是–da)來關閉它。你可以使用一些同時帶有這兩個標記的選項:
|
no arguments是指該標記適用於所有assertions。 |
|
packageName...是指該標記適用於packageName包及其子包中的所有類。 |
|
...是指該標記適用於目前的目錄下的未命名的(預設的)包。 |
|
className是指該標記只適用於className。 |
看以下這個命令列:
java -ea:foo.bar... -da:foo.bar.old MyClass |
它用於開啟除了foo.bar.old之外的foo.bar包及其子目錄中的assertions。
如何及何時使用Assertion
一個Java assertion有兩種形式。第一種形式經實踐證明是可取的:
assert some_boolean_expression; |
這就是說如果some_boolean_expression的值是false,則會被拋出一個AssertionError。注意這是一個錯誤,而不是一個異常;同樣地,它被當作一個非檢查異常(unchecked exception)來對待。(想要瞭解更多關於錯誤和異常之間的區別,請查閱我的另一篇文章“錯誤與異常”。)
另一種更為複雜形式的assert語句提供了一些更多的功能:
assert some_boolean_expression : some_non-void_expression |
這種形式比其前一種來說更加有用。第二個運算式some_non-void_expression被傳入用於AssertionError的構造器中。它能夠顯示更多發生在assertion失敗時的資訊。注意第二個參數可能會是任何對象或基本類型(包括null)。
列表1提供了一個簡單的使用第二種assert語句形式的範例。由於AssertionError是一個非檢查異常,所以沒必要去捕獲它(在列表1中由於示範說明的原因而對它進行了捕獲)。實際上,忽略(不去捕獲)AssertionErrors可能看起來也挺好,但你不應該這麼做,因為這樣一來可能會使應用程式處於一種不穩定的狀態下,尤其是對一個Swing-based程式來說更是如此。
有一些不能使用assertions的情況,比如試著用以下代碼找到問題:
assert isValid( myObject ); |
儘管這麼做看起來像是一個好辦法,但是想想看當assertion關閉時該怎麼辦――記住這是它的預設狀態:這個isValid方法將無法執行!特別是,一些行為(方法、操作等等)不能被用於這個assert語句的第一個參數,因為(除非有其他特別指定)它將永遠無法執行。
你可能想知道如何編寫開啟assertions的代碼,雖然這並不是一個好主意,但它會對已知的有依賴關係(dependency)的代碼很有協助。為此Sun提供了這個小技巧:
boolean assertsEnabled = false; // here's the trick assert assertsEnabled = true; if( !assertsEnabled ) throw new RuntimeException( "Asserts must be enabled!");} |
你可以將這段代碼用於任何需要開啟assertion的靜態初始化類中。如果assertion是關閉的,那麼assert語句將無法執行並會拋出一個異常;否則便會繼續執行,條件失效。
解決相容性問題
Java的assertion功能是一個語言特性,而不是API效能的擴充。Assertions代表了Java語言在多個版本間的首次顯著的改變但同時也將二進位相容性的問題帶了回來。這就意味著編譯到支援assertions的程式將無法在老版本JRE中運行。為了使開發人員更容易地建立帶有assertions的程式,Sun採取了謹慎的方法。JDK 1.4版本中程式的預設狀態是不支援assertion的,而用assertions編譯的代碼會產生以下響應:
warning: as of release 1.4, assert is a keyword, and may not be used as an identifier |
除了這個warning以外,使用assert關鍵字還會導致許多編譯錯誤。為了實現用assertions來編譯器,你需要使用一個–source 1.4標記。比如,在列表1中顯示的編譯命令代碼:
javac -source 1.4 Assert.java |
Java新的assertion功能為開發人員使用先進的技術(比如Design By Contract)來建立穩定的、高品質的代碼提供了新的方法。你需要考慮我提到的問題,但我想你也會認同這個新功能在Java語言中是相當受歡迎的
--列表1---.
| 用assert進行檢測 列表1.這個簡單的範例用來示範如何使用assertions來檢測那些可預知但不理想的結果。
public class Assert{ public static void main(String[] args) { try { doSomething(); } catch(AssertionError error) { error.printStackTrace(); } } public static int doSomething() { int i = 2; assert i != 2 : "i was 2 for some reason"; return i; }} |
|
關於作者:
Josh Street是Bank of America的方案架構師。你可以通過rjstreet@computer.org和他聯絡。