開(kāi)心一笑
【一大哥去醫(yī)院看病何恶。
醫(yī)生問(wèn):你得了什么材踝丁?
大哥說(shuō): 我得了間接性失憶癥细层。
醫(yī)生問(wèn):具體什么癥狀惜辑?
大哥說(shuō):我一看到漂亮的姑娘就忘記自己已結(jié)婚了。
醫(yī)生說(shuō):滾滾滾疫赎,這病我自己都沒(méi)治好盛撑!】
提出問(wèn)題
項(xiàng)目開(kāi)發(fā)中,使用方法要注意的一些事項(xiàng)捧搞?抵卫??
解決問(wèn)題
以下來(lái)自《Effective Java》中的讀書筆記:
檢查參數(shù)有效性
應(yīng)該在發(fā)生錯(cuò)誤之后盡快檢測(cè)出錯(cuò)誤
例如:
public BigInteger mod(BigInteger m){
//盡快檢查錯(cuò)誤
if(m.signum() <= 0){
throw new ArithmeticException("Modulus <= 0:" + m);
}
....
}
非共有的方法通常應(yīng)該使用斷言來(lái)檢查它們的參數(shù)实牡,具體做法如下:
private static void sort(long a[],int offset,int length){
assert a != null;
assert offset >= 0 && offset <= a.length;
assert length >=0 && length <=a.length -offset;
....//dosomethiing
}
必要時(shí)進(jìn)行保護(hù)性拷貝
對(duì)于構(gòu)造器的每個(gè)可變參數(shù)進(jìn)行保護(hù)性拷貝是必要的
例如:
public final class Period{
private final Date start;
private final Date end;
public Period(Date start,Date end){
....
this.start = start;
this.end = end;
}
public Date start(){
return start;
}
public Date end(){
return end;
}
}
Date start = new Date();
Date end = new Date();
Period p = new Period(start,end);
//注意問(wèn)題出現(xiàn)在這里
end.setYear(78);
修改后:
public Period(Date start,Date end){
....
this.start = new Date(start.getTime());
this.end = new Date(end.getTime());
}
注意,保護(hù)性拷貝是在檢查參數(shù)有效性之前進(jìn)行的陌僵,并且有效性檢查是針對(duì)拷貝之后的對(duì)象轴合,而不是針對(duì)原始的對(duì)象创坞。
雖然替換構(gòu)造器就可以成功避免上述攻擊,但是改變Period實(shí)例仍然是有可能的受葛,例如下面例子:
Date start = new Date();
Date end = new Date();
Period p = new Period(start,end);
//注意問(wèn)題出現(xiàn)在這里
p.end().setYear(78);
進(jìn)一步修改:
public Date start(){
return new Date(start.getTime());
}
public Date end(){
return new Date(end.getTime());
}
簡(jiǎn)而言之题涨,如果類具有從客戶端得到或者返回到客戶端的可變組件,類就必須保護(hù)性的拷貝這些組件偎谁。如果拷貝的成本受到限制,并且內(nèi)信任它的客戶端不會(huì)不恰當(dāng)?shù)男薷慕M件纲堵,就可以在文檔中指明客戶端的職責(zé)是不得修改受到影響的組件巡雨,以此來(lái)代替保護(hù)性拷貝。
謹(jǐn)慎設(shè)計(jì)方法簽名
- 謹(jǐn)慎地選擇方法的名稱席函。
- 不要過(guò)于追求提供便利的方法铐望。
- 避免過(guò)長(zhǎng)的參數(shù)列表。
有三種方法可以縮短過(guò)長(zhǎng)的參數(shù)列表茂附,第一種是把方法分解成多個(gè)方法正蛙,每個(gè)方法只需要這些參數(shù)的一個(gè)子集。第二種方法是創(chuàng)建輔助類用來(lái)保存參數(shù)的分組营曼。第三種是如果方法帶有多個(gè)參數(shù)乒验,尤其是當(dāng)它們中有些是可選的時(shí)候,最好定一個(gè)對(duì)象來(lái)表示所有參數(shù)蒂阱。(這些在之前文章都有提過(guò)了)
慎用可變參數(shù)
在重視性能的情況下锻全,使用可變參數(shù)需要特別小心,可變參數(shù)方法的每次調(diào)用都會(huì)導(dǎo)致進(jìn)行一次數(shù)組分配和初始化录煤。如果憑經(jīng)驗(yàn)確定無(wú)法承受這一成本鳄厌,但又需要可變參數(shù)的靈活性,還有一種模式可以讓你如愿以償妈踊。假設(shè)確定對(duì)某個(gè)方法95%的調(diào)用會(huì)有3個(gè)或者更少的參數(shù)部翘,就聲明改方法的5個(gè)重載,每個(gè)重載方法帶有0至3個(gè)普通參數(shù)响委,當(dāng)參數(shù)的數(shù)目超過(guò)3個(gè)時(shí)新思,就使用一個(gè)可變參數(shù)方法:
例如:
public void foo(){}
public void foo(int a1){}
public void foo(int a1,int a2){}
public void foo(int a1,int a2,int a3){}
public void foo(int a1,int a2,int a3,int ... rest){}
這種方法可能不太恰當(dāng),但是一旦需要它時(shí)赘风,它可就幫上大忙了夹囚。
總之,在定義參數(shù)數(shù)目不定的方法時(shí)邀窃,可變參數(shù)方法是一種很方便的方式荸哟,但是它們不應(yīng)該被過(guò)度濫用。如果使用不當(dāng)瞬捕,會(huì)產(chǎn)生混亂的結(jié)果鞍历。
返回零長(zhǎng)度的數(shù)組或集合,而不是null
例如:
public Cheese[] getCheeses(int size){
if(size == 0){
//這里返回null肪虎,是錯(cuò)誤的劣砍,因?yàn)檎{(diào)用改方法,還需要判斷這個(gè)null對(duì)象
return null;
}
}
正確做法:
private final List<Cheese> cheesesInStock = ...;
//定義final型的空數(shù)組
private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0];
public Cheese[] getCheeses(){
//返回空數(shù)組而不是null
return cheesesInStock.toArray(EMPTY_CHEESE_ARRAY);
}
同樣的對(duì)于集合(Collections.emptySet,emptyList,emptyMap等等)
public List<Cheese> getCheesesList(){
if(cheesesInStock.isEmpty()){
//返回不可變的空集合扇救,對(duì)于map
return Collections.emptyList();
}else{
return new ArrayList<Cheese>(cheesesInStock);
}
}
有時(shí)候會(huì)有人認(rèn)為:null返回值比零長(zhǎng)度數(shù)組更好刑枝,因?yàn)樗苊饬朔峙鋽?shù)組所需要的開(kāi)銷香嗓。
為所有導(dǎo)出的API元素編寫文檔注釋
例如:
/**
* <p> the method is ...<i>not<i>
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc} if the index is out of..
*/
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
方法的文檔注釋中每個(gè)參數(shù)都有一個(gè)@param標(biāo)簽(后面應(yīng)該是一個(gè)名詞),以及一個(gè)@return標(biāo)簽(除非返回為空)装畅,以及@throws標(biāo)簽(后面應(yīng)該是一個(gè)名詞)靠娱,@throws標(biāo)簽后應(yīng)該包含單詞"if",描述了異常將在什么樣的條件下會(huì)被拋出掠兄。
文檔注釋還使用了HTML標(biāo)簽(<p>和<i>).Javadoc工具會(huì)把文檔注釋翻譯成HTML
**{@code} **:表示該代碼片段以代碼字體進(jìn)行呈現(xiàn)
{@literal}:可以把小于號(hào)像云,大于號(hào)等包起來(lái),用來(lái)輸出這些字符蚂夕。
更多的文檔注釋苫费,可以看《Effective Java》對(duì)它的描述。
讀書感悟
來(lái)自亦舒《不易居》
- 現(xiàn)在還有誰(shuí)會(huì)照顧誰(shuí)一輩子双抽,那是多沉重的一個(gè)包袱百框。所以非自立不可。
- 你要改是因?yàn)槟阕约涸敢飧碾剐冢灰獮槿魏稳祟砦轮慌履侨藭?huì)令你失望,你又得打回原形慎菲。
其他
如果有帶給你一絲絲小快樂(lè)嫁蛇,就讓快樂(lè)繼續(xù)傳遞下去,歡迎轉(zhuǎn)載露该,點(diǎn)贊睬棚,頂,歡迎留下寶貴的意見(jiàn)解幼,多謝支持抑党!