【譯者序】
前一篇文章中原文作者漫談了null的來源與引發(fā)的常見問題,本文將開始對3中如今流行的null處理方式進(jìn)行討論,首先討論第一種方案
使用0來代替null
假設(shè)我們正在做一個(gè)在線購物的應(yīng)用,用戶可以在線下單購買商品。店家可以發(fā)布新商品,當(dāng)然當(dāng)這個(gè)新商品的價(jià)格還未定的時(shí)候,可以不填價(jià)格,先發(fā)布商品。
對于這個(gè)業(yè)務(wù)場景,下面哪種方案更好:
-- 不允許用戶讓價(jià)格為null,這樣可以完全阻止空指針錯(cuò)誤的發(fā)生。如果這個(gè)價(jià)格當(dāng)下確實(shí)未定,那就填0好了;
-- 如果價(jià)格當(dāng)下還未知,那就存null好了,給null敞開大門一次吧。
如果你去看看Stackoverflow上的這個(gè)問答——“用null還是用空集合”,你會發(fā)現(xiàn)這個(gè)問題的答案驚人的一致。
很多程序猿不知道怎么來區(qū)別處理“空”與“零”的關(guān)系,在我看來,若處理不當(dāng),這里面還會暗藏著嚴(yán)重的危機(jī)。比如,我一年多前想買個(gè)房子。我去一個(gè)房地產(chǎn)的網(wǎng)站,然后發(fā)現(xiàn)上面有很多房子的價(jià)格寫著“0”。可把我樂壞了:“沒逗我吧?免費(fèi)送房子??”但我當(dāng)然明白現(xiàn)實(shí)是殘酷的——他們只是沒寫價(jià)格而已。在這個(gè)例子里,你可能會毫不猶豫的說:“這還用問嗎?肯定是沒寫價(jià)格啊,誰沒事吃飽了撐著給你送房子啊。”
但是這網(wǎng)站上其他很多房子卻有寫了售價(jià),而且還有總體平均價(jià)格這些數(shù)據(jù)。我不知道這些均價(jià)計(jì)算里有沒有包括“0”,這樣一來搞不好會產(chǎn)生很多錯(cuò)誤。換句話說,100,000、120,000 和 “未知”,這三個(gè)的均價(jià)是多少?技術(shù)上來說當(dāng)然應(yīng)該是回答“未知”了。但你覺得這是用戶想看到的數(shù)據(jù)嗎?我們當(dāng)然希望看到的是明確的價(jià)格數(shù)字,像110,000這樣,但弄不好到頭來整出個(gè)73,333(這個(gè)數(shù)據(jù)我不知道原作者怎么突然冒出來的--譯者),那顯然是瞎扯淡了。而且,這個(gè)問題如果一旦發(fā)生在能夠在線支付的網(wǎng)站,那后果不堪設(shè)想。難道我們真的希望把“價(jià)格未定”弄得像“免費(fèi)”一樣?
用戶Jay這么說的:
我經(jīng)常弄不明白這個(gè)0和“無答案”之間的區(qū)別。許多次了,我用一個(gè)系統(tǒng)的時(shí)候它讓我輸入一個(gè)數(shù)字,我輸入0,然后它居然回我一個(gè)錯(cuò)誤,說我必須輸入一個(gè)值!?耍我呢?我不是已經(jīng)輸入了0么?但它就死活說0不行,我估計(jì)是因?yàn)樗九磺宄?和“無”之間的區(qū)別。
那如果我們采用第二種保留null的方案的話,網(wǎng)上商店會運(yùn)行得怎樣?很明顯,價(jià)格為0、莫名其妙的“零元購”將會被從根本上杜絕。
我們可以去對null做一個(gè)檢查,如果價(jià)格為null,那么顯示“價(jià)格未定”或者“請聯(lián)系我們”。如果忘記檢查了,那就會拋出另一個(gè)空指針錯(cuò)誤。這種做法當(dāng)然不討人喜歡,但是再怎么也比讓用戶在網(wǎng)上莫名其妙的免費(fèi)買房子要好。
這樣一來,均價(jià)的計(jì)算也不會出現(xiàn)問題了。
除了這些外,我們還可以發(fā)現(xiàn)更多與之類似的問題:
· 在使用String的時(shí)候,用空字符串或者用字符串"null"來代替本應(yīng)該是null的值
· 在使用boolean的時(shí)候,用false來代替本應(yīng)該是null的值
縱觀全局,總結(jié)如下:
保持用null,遠(yuǎn)比用非null的值來替代“無值”要好
沒錯(cuò),我們是增加了空指針錯(cuò)誤的風(fēng)險(xiǎn)。但是為了避免這種錯(cuò)誤,我們所付出的代價(jià)就是直接給用戶提供完全錯(cuò)誤的信息,甚至導(dǎo)致完全無法接受乃至災(zāi)難性的后果——比如房子突然被免費(fèi)“賣”出去了。
-- 如果程序因?yàn)榭罩羔樺e(cuò)誤崩潰了,用戶的確會不高興;
-- 但如果程序完全傳達(dá)錯(cuò)誤的信息并且提供極其愚蠢、不安全的信息給用戶,那用戶,會更加更加不高興。
-- 孰輕孰重,一目了然。
所以,我們真的需要對null說一聲愛你。
好了,這時(shí)候我們回到剛一開始我介紹的email的例子上來。我們?nèi)缦略O(shè)置:
String email = null;
System.out.println ( "Alice's email address is " + email );
有如下結(jié)果:
Alice's email address is null
在這個(gè)場景里,這個(gè)結(jié)果看起來還是可以接受的。但說實(shí)在的程序語言/編譯器不應(yīng)該這么來處理。像我們剛剛分析了,更好的做法應(yīng)該是拋出一個(gè)空指針異常,因?yàn)檫@樣一來程序員就可以很快的發(fā)現(xiàn)這里有問題。null是個(gè)很特殊的東西,所以我們也有必要去對它特殊對待。
經(jīng)過空指針錯(cuò)誤的提醒,程序猿這么一改,就舒服了:
if ( email != null ) {
System.out.println ( "Alice's email address is " + email );
} else {
System.out.println ( "Alice doesn't have an email address." );
}
【下一篇文章將分析第二種方案:空對象模式】