JSP中文網(wǎng)內(nèi)容管理系統(tǒng)(JCMS) JSP虛擬主機 網(wǎng)絡(luò)筆記本 網(wǎng)摘,圖片,筆記收藏 虛擬服務(wù)器 |
JSPCN文章目錄分類 |
緩存區(qū) [2581] |
圖片聲音 [17] |
JSP配置 [219] |
開發(fā)工具 [28] |
上傳問題 [27] |
時間相關(guān) [16] |
教程系列 [157] |
文件操作 [126] |
STRUTS [144] |
JSP實例 [89] |
中文問題 [69] |
數(shù)據(jù)庫 [212] |
JAVAMAIL [72] |
JSP基礎(chǔ) [136] |
JSP其他 [57] |
JAVABEAN [46] |
異常處理 [33] |
JMX [8] |
Servlet [98] |
J2ME [257] |
JAVA實例 [290] |
JAVA網(wǎng)絡(luò) [179] |
EJB [261] |
Hibernate [6] |
聲音圖片 [28] |
APPLET [78] |
JAVA線程 [90] |
J2EE [374] |
SUN [89] |
Java API [141] |
JAVA基礎(chǔ) [421] |
Spring [34] |
考試相關(guān) [63] |
JAVA類 [139] |
Application [115] |
Swing [26] |
XML [163] |
JS基礎(chǔ) [184] |
asp筆記 [7] |
RSS [1] |
B/S開發(fā) [12] |
B/S其他 [7] |
代碼收集 [8] |
原子代碼 [3] |
eclipse [42] |
Tomcat [93] |
Jbuilder [57] |
RESIN [25] |
JBOSS [25] |
weblogic [56] |
ORACLE [92] |
sql server [33] |
MYSQL [39] |
WWW服務(wù) [6] |
常見問題 [13] |
郵件服務(wù) [4] |
相關(guān)說明 [1] | |
熱點文章鏈接 |
JMX架構(gòu)的了解 [1060] J2SE1.4的I/O新特性 [567] J2SE 1.4 中assertion 功能介紹 [476] Jcreater+MotoJ2SDK的配置與使用心得 [445] 使用JMX監(jiān)控應(yīng)用程序內(nèi)、外部的狀況 [383] 學(xué)習(xí)J2SE過程中的30個基本概念 [336] 安裝J2SE [308] J2SE
1.5版本的新特性一覽 [263]
|
|
|
J2SE 1.4 中assertion 功能介紹 |
作者:未知 文章來源:www.jspcn.net 訪問次數(shù): 次 加入時間:2005-01-19 |
|
摘要 J2SE 1.4
在JAVA中新增添了assertion(暫譯作斷定)功能。 最簡單的情形下,在JAVA代碼中任一行可以寫入一條布爾表達式,
在這一行代碼的最前面加上assert關(guān)鍵字,就可以實現(xiàn)這樣的功能: 如果表達式為真,則代碼繼續(xù)執(zhí)行;否則,拋出異常。為了實現(xiàn)這項功能,
在JAVA中新添加了assert關(guān)鍵字,AssertionError類, java.lang.ClassLoader中增加了幾個新的方法。
本文章詳細介紹了assert關(guān)鍵字的使用,
從命令行控制assertion功能,從代碼內(nèi)部控制assertion功能,以及何時使用assertion功能等內(nèi)容。下文中提到assert時特指assert關(guān)鍵字,而提到assertion則表示斷定語句或斷定功能。
作者: 甲子
assertion功能提供了一種在代碼中進行正確性檢查的機制,這種檢查通常用于開發(fā)和調(diào)試階段,到了軟件完成部署后就可以關(guān)閉。這使得程序員可以在代碼中加入調(diào)試檢查語句,同時又可以在軟件部署后關(guān)閉該功能而避免對軟件速度和內(nèi)存消耗的影響?;旧?,assertion功能就是JAVA中的一種新的錯誤檢查機制,只不過這項功能可以根據(jù)需要關(guān)閉。
通常在C和C++中,斷定功能語句是可以通過預(yù)處理過程而不編譯進最終的執(zhí)行代碼,由于JAVA中沒有宏功能,所以在以前的java版本中斷定功能沒有被廣泛的使用,在JDK1.4中通過增加assert關(guān)鍵字改變了這種狀況。
這項新功能最重要的特點是斷定語句可以在運行時任意的開啟或關(guān)閉,這意味著這些起錯誤檢查功能的語句不必在開發(fā)過程結(jié)束后從源代碼中刪除。
assertion語法非常簡單,但正確的使用能幫助我們編寫出健壯(ROBAST)可靠的代碼。這篇文章中,我們不僅學(xué)習(xí)如何編寫assertion語句,更要討論應(yīng)該在什么情況下使用assertion語句。
一、assertion語法基本知識
我們可以用新的JAVA關(guān)鍵字assert來書寫斷定語句。一條斷定語句有以下兩種合法的形式:
assert
expression1; assert expression1 : expression2;
expression1是一條被判斷的布爾表達式,必須保證在程序執(zhí)行過程中它的值一定是真;expression2是可選的,用于在expression1為假時,傳遞給拋出的異常AssertionError的構(gòu)造器,因此expression2的類型必須是合法的AssertionError構(gòu)造器的參數(shù)類型。以下是幾條斷定語句的例子:
assert
0 < value; assert ref != null; assert count == (oldCount + 1);
assert ref.m1(parm);
assert關(guān)鍵字后面的表達式一定要是boolean類型,否則編譯時就會出錯。
以下是使用斷定語句的一個完整例子(見粗體語句行):
public
class aClass { public void aMethod( int value ) { assert value >=
0; System.out.println( "OK" ); } public static void main( String[] args
){ aClass foo = new aClass(); System.out.print( "aClass.aMethod( 1 ): "
); foo.aMethod( 1 ); System.out.print( "aClass.aMethod( -1 ): "
); foo.aMethod( -1 ); } }
這段程序通過語句 assert value >= 0;
來判斷傳入aMethod方法中的參數(shù)是否不小于0,如果傳入一個負數(shù),則會觸發(fā)AssertionError的異常。
為了和J2SE 1.4
以前的程序兼容,在JDK1.4 中的javac 和 java
命令在默認情況下都是關(guān)閉assertion功能的,即不允許使用assert作為關(guān)鍵字,這就保證了如果你以前編寫的程序中如果使用了assert作為變量名或是方法名,程序不必修改仍然可以運行。但需要注意的是,這些程序是無法使用JDK1.4
的javac進行重新編譯的,只能使用JDK1.3或之前的版本編譯。為了編譯我們前面寫的小程序,首先要使用符合J2SE 1.4
的編譯器,同時還要使用幾個命令行參數(shù)來使編譯器啟用assertion功能。
使用以下的命令來編譯aClass.java:
javac
-source 1.4 aClass.java
如果我們使用 java aClass
來運行這段程序,就會發(fā)現(xiàn)assertion語句實際上并未得到執(zhí)行,和javac一樣,java命令在默認情況下,關(guān)閉了assertion功能,因而會忽略assertion語句。如何啟用assertion語句將在下一節(jié)討論。
二、通過命令行控制assertion功能
assertion語句的一項最重要的特點是它可以被關(guān)閉,關(guān)閉的作用是這條代碼雖然仍存在于程序當中,但程序運行時,JVM會忽略它的存在,不予執(zhí)行,這樣代碼的運行速度不會由于assertion語句的存在而受到影響,如果代碼執(zhí)行過程中出現(xiàn)了問題,我們又可以啟用assertion語句,幫助我們進行分析判斷。默認情況下,這項功能是關(guān)閉的。(提示:本小節(jié)介紹的命令行參數(shù)都是針對SUN提供的JDK1.4而言,如果使用其他公司的JDK則未必會完全一樣。)
JDK1.4 中,通過java命令的命令行選項 -ea (-enableassertions
的縮寫)來啟用。以下兩個命令是等效的:
java -ea myPackage.myProgram java
-enableassertions myPackage.myProgram
同樣,我們通過 -da (-disableassertions
的縮寫)來關(guān)閉assertion功能:
java -da myPackage.myProgram java
-disableassertions
myPackage.myProgram
assertion功能還可以針對特定的包(package)或類(class)分別啟用和關(guān)閉。針對類時,使用完整的類名;針對包時,包名后面緊跟“...”:
java -ea: myPackage.myProgram java
-da:... myPackage.myProgram
在一個java命令中使用多項 -ea -da
參數(shù)時,后面的參數(shù)設(shè)定會覆蓋前面參數(shù)的設(shè)定,比如我們可以默認啟用所有的assertion功能,但針對特定的包卻關(guān)閉此功能:
java -ea
-da:...
myPackage.myProgram
對于未命名的包(位于當前目錄中)都屬于默認包,可以使用以下的命令控制:
java
-ea:... myPackage.myProgram java -da:...
myPackage.myProgram
對于隨JVM安裝時自己附帶的所有系統(tǒng)類,可以分別使用
-esa(-enablesystemassertions)和-dsa(-disablesystemassertions)來控制assertion功能的啟用和關(guān)閉。在表1.1中列出了控制assertion功能參數(shù)的所有用法。
表1
JDK1.4 中java命令和assertion功能有關(guān)的命令行參數(shù)
命令行參數(shù) 實例 含義 -ea Java
-ea 啟用除系統(tǒng)類外所有類的assertion -da Java -da 關(guān)閉除系統(tǒng)類外所有類的assertion
-ea: Java -ea:AssertionClass 啟用AssertionClass類的assertion
-da: Java -da:AssertionClass 關(guān)閉AssertionClass類的assertion
-ea: Java -ea:pkg0... 啟用pkg0包的assertion
-da: Java -da:pkg0... 關(guān)閉pkg0包的assertion -esa
Java -esa 啟用系統(tǒng)類中的assertion -dsa Java -dsa 關(guān)閉系統(tǒng)類中的assertion
至此,我們前面編寫的小程序aClass可以用以下的任意命令運行:
java -ea aClass java
-ea:aClass aClass java -ea:... aClass
運行結(jié)果如下: aClass.aMethod(
1 ): OK aClass.aMethod( -1 ): java.lang.AssertionError at
aClass.aMethod(aClass.java:3) at aClass.main(aClass.java:12) Exception in
thread
"main"
三、assertion命令行參數(shù)之間的繼承關(guān)系
assertion功能的啟用和關(guān)閉可以一直控制到每一個類,一個命令行可以容納任意多個-ea
-da 參數(shù),這些參數(shù)之間是如何相互起作用的,基本上遵循兩個原則:特定具體的設(shè)定優(yōu)先于一般的設(shè)定,后面的設(shè)定優(yōu)先于前面的設(shè)定。我們看下面的例子:
// Base.java package tmp; public class Base{ public void m1(
boolean test ){ assert test : "Assertion failed: test is " +
test; System.out.println( "OK" ); } } //
Derived.java // package tmp.sub; import tmp.Base; public class
Derived extends Base{ public void m2( boolean test ){ assert test :
"Assertion failed: test is " + test; System.out.println( "OK"
); } public static void printAssertionError( AssertionError ae
){ StackTraceElement[] stackTraceElements =
ae.getStackTrace(); StackTraceElement stackTraceElement = stackTraceElements[
0 ]; System.err.println( "AssertionError" ); System.err.println( " class=
" + stackTraceElement.getClassName() ); System.err.println( " method= " +
stackTraceElement.getMethodName() ); System.err.println( " message= " +
ae.getMessage() ); } public static void main( String[] args
){ try{ Derived derived = new Derived(); System.out.print( "derived.m1(
false ): " ); derived.m1( false ); System.out.print( "derived.m2( false ):
" ); derived.m2( false ); }catch( AssertionError ae
){ printAssertionError( ae
); } } }
Base類和Derived類個有一個方法m1和m2,因為Derived是Base的子類,所以它同時繼承了方法m1。
首先在啟用所有類的assertion功能后,運行程序:
java
-ea tmp.sub.Derived
derived.m1( false ): AssertionError class=
tmp.Base method= m1 message= Assertion failed: test is
false
然后,我們單獨關(guān)閉Base類的assertion功能的情況下,運行程序:
java -ea
-da:tmp.Base tmp.sub.Derived
derived.m1( false ): OK derived.m2( false
): AssertionError class= tmp.sub.Derived method= m2 message= Assertion
failed: test is
false
可以看到,derived.m1(false)語句沒有觸發(fā)異常,顯然這條語句是受到Base類的assertion功能狀態(tài)控制的。如果繼續(xù)研究,會發(fā)現(xiàn)以下兩條語句的作用是一樣的:
java
-da:tmp.Base -ea:tmp... tmp.sub.Derived java -ea:tmp... -da:tmp.Base
tmp.sub.Derived
這說明前面提到的兩條原則是在起作用。
四、在程序代碼中控制assertion功能
assertion功能的啟用和關(guān)閉也可以通過代碼內(nèi)部進行控制,一般情況下,是不需要這樣做的,除非我們是在編寫java程序的調(diào)試器,或是某個控制java程序運行的程序。
每一個java類都有一個代表其assertion功能啟用與否的標識符。當程序運行到assertion語句行時,JVM就會檢查這行assertion語句所在類的assertion標識符,如果是true,那就會執(zhí)行這條語句,否則就忽略這條語句。
這個assertion標識符可以ClassLoader的以下方法設(shè)定:
public
void setClassAssertionStatus(String className, boolean
enabled);
className--需要設(shè)定assertion標識符的類
enabled--assertion功能啟用或是關(guān)閉
這個assertion標識符也可以針對整個包一起控制,用ClassLoader的另一個方法設(shè)定:
public
void setPackageAssertionStatus(String packageName, boolean
enabled);
className--需要設(shè)定assertion標識符的包
enabled--assertion功能啟用或是關(guān)閉
注意這個方法對于包packageName
的所有子包也起作用。
ClassLoader還有一個方法可以設(shè)定所有通過此ClassLoader裝載的類的默認assertion狀態(tài):
public
void setDefaultAssertionStatus(boolean
enabled);
最后,ClassLoader有一個方法可以清除所有以前進行的設(shè)定:
public void
clearAssertionStatus();
Class類也新增加了一個與assertion功能有關(guān)的方法,利用這個方法可以知道某個類的assertion功能是啟用的還是關(guān)閉的:
public
boolean
desiredAssertionStatus();
注意:通過ClassLoader來設(shè)定assertion標識符只會影響此后通過該ClassLoader裝載的類,而不會改變此前已經(jīng)裝載的類的assertion標識符狀態(tài)。
五、AssertionError介紹
java.lang包增加了AssertinError類,它是Error的直接子類,因此代表程序出現(xiàn)了嚴重的錯誤,這種異常通常是不需要程序員使用catch語句捕捉的。AssertionError除了一個不帶參數(shù)的缺省構(gòu)造器外,還有7個帶單個參數(shù)的構(gòu)造器,分別為:
object
boolean
char
int
long
float
double
我們前面提到的assertion語句的兩種語法形式如下:
assert
expression1; assert expression1 : expression2;
第一種形式如果拋出異常,則調(diào)用AssertionError的缺省構(gòu)造器,對于第二種形式,則根據(jù)expression2值的類型,分別調(diào)用7種單參數(shù)構(gòu)造器中的一種。
下面我們對例一稍做修改,看看第二種assertion表達式的用法:
public
class aClass2{ public void m1( int value ){ assert 0 <= value : "Value
must be non-negative: value= " + value; System.out.println( "OK"
); } public static void printAssertionError( AssertionError ae
){ StackTraceElement[] stackTraceElements =
ae.getStackTrace(); StackTraceElement stackTraceElement = stackTraceElements[
0 ]; System.err.println( "AssertionError" ); System.err.println( " class=
" + stackTraceElement.getClassName() ); System.err.println( " method= " +
stackTraceElement.getMethodName() ); System.err.println( " message= " +
ae.getMessage() ); } public static void main( String[] args
){ try{ aClass2 fooBar = new aClass2 (); System.out.print( "
aClass2.m1( 1 ): " ); fooBar.m1( 1 ); System.out.print( " aClass2.m1( -1
): " ); fooBar.m1( -1 ); } catch( AssertionError ae
){ printAssertionError( ae
); } } }
運行結(jié)果如下:
aClass2.m1( 1 ): OK aClass2.m1(
-1 ): AssertionError class= aClass2 method= m1 message= Value must be
non-negative: value= -1
從以上的結(jié)果可以可以發(fā)現(xiàn),assertion語句 :
之后的參數(shù)被傳遞給了AssertionError的構(gòu)造器,成為StackTrace的一部分。
因為AssertionError代表正常時不應(yīng)該出現(xiàn)的錯誤,所以一旦出現(xiàn),應(yīng)盡快拋出,中止程序的執(zhí)行,以引起程序維護人員的注意。但有時我們也需要捕捉AssertionError,執(zhí)行一些任務(wù),然后,重新拋出AssertionError。比如,我們的程序在網(wǎng)絡(luò)中的某處有控制臺監(jiān)控整個系統(tǒng)的運行,我們就需要首先獲得關(guān)于AssertionError的異常信息,通過網(wǎng)絡(luò)傳送給控制臺,然后再拋出AssertionError,中止程序,就象例3做的那樣:
public
void method() { AssertionError ae = null; try { int a =
anotherMethod(); // ... assert i==10; // ... }catch( AssertionError
ae2 ){ ae = ae2; StackTraceElement stes[] = ae.getStackTrace(); if
(stes.length>0) { StackTraceElement first =
stes[0]; System.out.println( "NOTE: Assertion failure in
"+ first.getFileName()+" at line "+first.getLineNumber() ); } else
{ System.out.println( "NOTE: No info available." ); } throw
ae; } }
六、是否使用assertion的幾條準則
對assertion而言,重要的不是如何使用,而是何時何地使用。這一節(jié)將介紹幾條準則,歸納在表2當中,可以幫助我們在決定是否應(yīng)該使用assertion語句這樣的問題時,做出正確的判斷。
表2:是否使用assertion語句的判斷原則
應(yīng)該使用的情形 不應(yīng)該使用的情形
用于保證內(nèi)部數(shù)據(jù)結(jié)構(gòu)的正確 不用于保證命令行參數(shù)的正確
用于保證私有(private)方法參數(shù)的正確 不用于保證公共(public)方法參數(shù)的正確
用于檢查任何方法結(jié)束時狀態(tài)的正確 不用于檢查外界對公共方法的使用是否正確
用于檢查決不應(yīng)該出現(xiàn)的狀態(tài) 不用于保證應(yīng)該由用戶提供的信息的正確性
用于檢查決不應(yīng)該出現(xiàn)的狀態(tài),即使你肯定它不會發(fā)生 不要用于代替if語句 用于在任何方法的開始檢查相關(guān)的初始狀態(tài) 不要用做外部控制條件
用于檢查一個長循環(huán)執(zhí)行過程中的的某些狀態(tài)
不要用于檢查編譯器、操作系統(tǒng)、硬件的正確性,除非在調(diào)試過程中你有充分的理由相信它們有錯誤
assertion語句并不是if (expression) then
語句的簡寫,相反,它是保證代碼健壯的重要手段。重要的是正確的區(qū)分何時使用assertion,何時使用一般的條件表達式。以下幾條是使用assertion語句時需注意的情形。
不要使用assertion來保證明命令行參數(shù)的正確
使用命令行參數(shù)的程序都要檢查這些參數(shù)的正確性,但這應(yīng)該通過正常的條件檢查來實現(xiàn)。以下就是一個錯誤使用assertion的例子。
public
class Application{ static public void main( String args[] ) { //
BAD!! assert args.length == 3; int a = Integer.parseInt( args[0] ); int
b = Integer.parseInt( args[1] ); int c = Integer.parseInt( args[2]
); } }
如果你的程序必須有三個參數(shù),否則不能運行的話,那更好的方法是拋出適當?shù)腞untimeException:
public
class App{ static public void main( String args[] ) { if (args.length !=
3) throw new RuntimeException( "Usage: a b c" ); int a =
Integer.parseInt( args[0] ); int b = Integer.parseInt( args[1] ); int c =
Integer.parseInt( args[2]
); } }
assertion語句的作用是保證程序內(nèi)部的一致性,而不是用戶與程序之間的一致性。
使用assertion來保證傳遞給私有方法參數(shù)的正確性
以下的私有方法有兩個參數(shù),一個是必須的,一個是可選的。
private
void method( Object required, Object optional ) { assert( required != null )
: "method():
required=null"; }
通常,私有方法只是在類的內(nèi)部被調(diào)用,因而是程序員可以控制的,我們可以預(yù)期它的狀態(tài)是正確和一致的。我們也就可以假設(shè)對它的調(diào)用是正確的,這自然包括調(diào)用參數(shù)的正確,因此可以使用assertion語句來保證這種準確性。
這一原則同樣適用protected和package-protected方法。
不要使用assertion來保證傳遞給公共方法參數(shù)的正確性
下面這個公共方法有兩個參數(shù),source和sink分別代表頭和尾,它們之間是互連的。在斷開它們之間的連接之前,必須保證它們之間已經(jīng)是互連的:
public
void disconnect( Source source, sink sink ) { // BAD!! assert
source.isConnected( sink ) : "disconnect(): not connected
"+source+","+sink; }
由于這個方法是public,因此source和sink之間的關(guān)系是我們不能控制的。這種我們不能保證正確的場合是不適合使用assertion語句的。
更重要的是,public方法可能被許多不同的程序調(diào)用,它必須保證在不同的調(diào)用情形下,它的接口特性是完全相同的。由于assertion語句是不能保證會被運行的,這取決于運行環(huán)境中的assertion功能是否被啟用,如果assertion功能未被啟用,就無法保證這個public
方法參數(shù)的正確。
這種情況下,你應(yīng)該假設(shè)調(diào)用代碼是有可能出錯的,拋出適當?shù)漠惓#?br /> public void disconnect(
Source source, sink sink ) throws IOException{ if (!source.isConnected( sink
)) { throw new IOException( "disconnect(): not connected "+source+","+sink
); } }
不要使用assertion來保證外部對公共方法的用法模式是否正確
下面這個public類可能處于兩種狀態(tài),open或是closed。打開一個已經(jīng)打開的Connection,關(guān)閉一個已經(jīng)關(guān)閉的Connection都是錯誤的。但我們不應(yīng)該使用assertion功能來保證這種錯誤不會發(fā)生:
public
class Connection{ private boolean isOpen = false; public void open()
{ // ... isOpen = true; } public void close() { //
BAD!! assert isOpen : "Cannot close a connection that is not open!"; //
... } }
我們只有在Connection類是private類時,或者保證這個類對外界是不可見的,并且愿意相信所有使用這個類的的代碼都是正確的情況下,才可以使用這種用法。
然而,Connection類是被公共使用的,完全有可能某個使用Connection類的程序存在漏洞,而試圖關(guān)閉一個未打開的連接。由于存在這種可能,使用拋出異常是更適合的:
public
class Connection{ private boolean isOpen = false; public void open()
{ // ... isOpen = true; } public void close() throws
ConnectionException { if (!isOpen) { throw new
ConnectionException( "Cannot close a connection that is not open!"
); } //
... } }
不要使用assertion來保證對用戶提供的某項信息的要求
在下面這段代碼里,程序員使用assertion來確保郵政編碼有5或9位數(shù)字:
public
void processZipCode( String zipCode ) { if (zipCode.length() == 5) { //
... } else if (zipCode.length() == 9) { // ... } else { //
BAD!! assert false : "Only 5- and 9-digit zip codes
supported"; } }
assertion應(yīng)該用來保證內(nèi)部的一致性,而不是保證正確的輸入。上面的代碼應(yīng)該在錯誤是直接拋出異常:
public
void processZipCode( String zipCode ) throws ZipCodeException { if
(zipCode.length() == 5) { // ... } else if (zipCode.length() == 9) { //
... } else { throw new ZipCodeException( "Only 5- and 9-digit zip codes
supported"
); } }
使用assert來保證對內(nèi)部數(shù)據(jù)結(jié)構(gòu)方面假設(shè)的正確
下面的私有方法的參數(shù)是3個整數(shù)構(gòu)成的數(shù)組。我們可以用assertion來確認這個數(shù)組有正確的長度:
private
void showDate( int array[] ) { assert( array.length==3
); }
我們預(yù)期對這個方法的調(diào)用都是正確的,即只提供長度為3的數(shù)組,assertion語句在此正是起到這個作用。
Java語言對數(shù)組已經(jīng)有邊界檢查的功能,這保證程序不會讀取數(shù)組邊界之外的值,這段代碼中assertion語句的作用就不如在C或C++中的作用那么重要,但也不意味著這是多余的。
使用assertion來檢查任何方法將結(jié)束時狀態(tài)
我們看下面的例子是如何在方法返回之前檢查最后的狀態(tài):
public
class Connection{ private boolean isOpen = false; public void open()
{ // ... isOpen = true; // ... assert isOpen; } public void
close() throws ConnectionException { if (!isOpen) { throw new
ConnectionException( "Cannot close a connection that is not open!"
); } // ... isOpen = false; // ... assert
!isOpen; } }
這樣做的好處是這些方法內(nèi)部的代碼不管如何復(fù)雜,或是經(jīng)過多少修改變動,利用最后的一條assertion語句我們都可以保證方法返回時某個狀態(tài)的正確。
使用assertion檢查不應(yīng)該發(fā)生的狀態(tài)
下面的代碼正是起到這種作用:
private
int getValue() { if (/* something */) { return 0; } else if (/*
something else */) { return 1; } else { return 2; } } public
void method() { int a = getValue(); // returns 0, 1, or 2 if (a==0)
{ // deal with 0 ... } else if (a==1) { // deal with 1 ... } else if
(a==2) { // deal with 2 ... } else { assert false : "Impossible: a is
out of
range"; } } 這個例子中,getValue的返回值只能是0,1,2,正常時出現(xiàn)其他值的情形是不應(yīng)該的,使用assertion來確保這一點是最合適的。
提示:一個很好的編程習(xí)慣是對每組if
else 語句總是寫一條最后的else語句來包括所有的其他情況,如果你能保證程序一定不會進入這條語句,加進一條assert
false;。
使用assertion檢查任何方法開始時的初始狀態(tài)
在這個例子里,方法processZipCode()必須保證zipCode的格式是有效的,才進行進一步的處理:
public
void processZipCode( String zipCode ) { assert zipCodeMapIsValid(); //
... }
這樣做可以使程序中的漏洞及早被發(fā)現(xiàn)。
最后的原則:有勝于無
加入assertion語句是非常簡單的,可以在代碼編寫的任何階段加入,而且對程序運行速度性能等方面帶來的影響也是輕微的,因此如果你對程序的某些環(huán)節(jié)有懷疑,不確定的時候,盡管加入assertion語句。一條永遠不會觸發(fā)的assertion語句并沒有什么壞處,但如果應(yīng)該觸發(fā)卻沒有assertion語句存在,那時給我們帶來的麻煩卻是巨大的。 | | |