1.6 要決斷:使用Java斷言
Java5+
“編程人員總是正確的—— 是編譯器和解釋器造成的錯(cuò)誤。”我確信你認(rèn)同這種說法。作為編程人員,經(jīng)常要對變量的值做出假設(shè)并且基于此編寫代碼。盡管非常不愿意承認(rèn)可能在設(shè)計(jì)或?qū)崿F(xiàn)上有錯(cuò)誤,但有時(shí)變量和參數(shù)卻沒有獲得期望的值。
當(dāng)設(shè)計(jì)和編寫代碼時(shí),只有在最初的假設(shè)仍然成立的情況下代碼才能正確運(yùn)行。如果沒有任何有關(guān)這些假設(shè)的聲明,那么閱讀代碼的任何人(甚至你自己)都不清楚它們的含義是什么。從而導(dǎo)致今后的改動(dòng)可能會(huì)違反這些假設(shè)并引入難以查找的錯(cuò)誤。通常,在注釋中說明假設(shè)能使以后修改代碼的人避免出錯(cuò)。
使用注釋來說明假設(shè)是一個(gè)好的開始。但是當(dāng)出現(xiàn)違反假設(shè)的情況時(shí),程序有時(shí)會(huì)繼續(xù)運(yùn)行就像未出現(xiàn)任何問題一樣。一些情況下,開發(fā)人員能夠馬上看到結(jié)果,并且可以糾正出現(xiàn)的問題。但在另一些情況下,存在一個(gè)潛伏的錯(cuò)誤時(shí),可能會(huì)對應(yīng)用程序的其他部分造成負(fù)面影響,對于分布式系統(tǒng)而言,則可能會(huì)對完全不同的另一個(gè)應(yīng)用程序造成負(fù)面影響!跟蹤這樣的問題非常困難。
Java 1.4在語言中添加了斷言特性來簡化測試和調(diào)試,加強(qiáng)文檔編制并提高基于Java的可維護(hù)性。可以使用一個(gè)布爾表達(dá)式來創(chuàng)建一個(gè)斷言,以便測試有關(guān)系統(tǒng)的當(dāng)前狀態(tài)所假定的某些情況。如果斷言失敗,運(yùn)行庫會(huì)拋出一個(gè)AssertionError。下面給出一個(gè)很簡單的斷言:
String name = "Brian"; |
這里,可以確定在給name分配了值“Brian”后它的值將不會(huì)為空。如果它的值為空,則出現(xiàn)了某種嚴(yán)重的錯(cuò)誤!此斷言是當(dāng)時(shí)在程序中對變量的值所做的假定的聲明。為如此簡單的例子做這種聲明看似可笑和多余。但是,當(dāng)多個(gè)方法會(huì)影響一個(gè)對象的狀態(tài)時(shí),這種方法是有效的。在下面的示例中,示例了這樣一個(gè)斷言,即在向新員工分配任何任務(wù)之前必須已經(jīng)指派了一名管理人員。
Employee worker = |
通常,在對某個(gè)對象執(zhí)行關(guān)鍵操作時(shí)會(huì)需要對它創(chuàng)建斷言。這有助于增強(qiáng)代碼的健壯性,比如如果在程序中出現(xiàn)了某種錯(cuò)誤,可以更方便地調(diào)試程序。這樣做要比程序在某處執(zhí)行失敗造成不良后果來發(fā)現(xiàn)錯(cuò)誤要好得多。當(dāng)知道程序失敗是由于它違反了假設(shè)而引起的時(shí)候,跟蹤失敗的原因要簡單得多。在這個(gè)代碼樣例中,使用了assert選項(xiàng)來返回更有用的信息。沒有此選項(xiàng)時(shí),除了行號之外將無法得到有關(guān)斷言的標(biāo)識信息。
在某些版本的編譯器上,當(dāng)編譯源代碼時(shí)需要使用一個(gè)命令選項(xiàng)來設(shè)置編譯器的源兼容性模式(取決于編譯器的版本,如1.4或1.5)。
javac -source 1.5 MyClass.java |
現(xiàn)在強(qiáng)制斷言失敗并觀察會(huì)出現(xiàn)什么情況:
public class AssertBad { |
默認(rèn)情況下,運(yùn)行時(shí)環(huán)境不支持?jǐn)嘌?,必須使用ea(允許斷言)命令選項(xiàng)來啟動(dòng)JRE。上面的代碼會(huì)引起以下的結(jié)果:
C:\projects\wcj1> java -ea AssertBad |
要記住斷言是用來對那些不應(yīng)該出現(xiàn)的情況進(jìn)行實(shí)際的“健全性檢查”,因此不應(yīng)該使用它們來替代常規(guī)的錯(cuò)誤檢查。
警告:
不要讓斷言語句更改代碼中的狀態(tài)/值。否則當(dāng)最終關(guān)閉斷言時(shí),代碼的行為方式將不同于啟用斷言時(shí)代碼的行為。例如,不要?jiǎng)?chuàng)建如下的斷言:
assert (++i > 10); // BAD: i changes only with assertions enabled! |
通常,在整個(gè)開發(fā)階段都會(huì)啟用斷言。一旦完全測試了系統(tǒng)并將它移送到產(chǎn)品環(huán)境時(shí),則希望禁用斷言,因?yàn)檫@樣做會(huì)略微改善性能。但是不要改動(dòng)代碼來完成此操作,并且也不要?jiǎng)h除斷言。不管怎樣,為了編制文檔的目的,斷言也應(yīng)保留在代碼中。這樣,當(dāng)以后更改代碼時(shí),會(huì)提醒程序員要保持所有假設(shè)都是有效的,并且這也是可測試的。