關於《effectivity Java》閱讀筆記
第八章 – 通用的程序設計
關於局部變量的初始化
將局部變量最小化,可以增加代碼的可讀性和可維護性,並降低出錯的可能性。
要使局部變量的作用域最小化,最好的做法就是在第一次使用它的時候進行聲明。
如果變量在使用之前聲明,會影響影響試圖理解代碼的讀者,分散他們的注意力。耗費時間尋找變量聲明的地方。幾乎每個局部變量都應該包含一個初始化表達式,如果一個變量被一個方法初始化,而這個方法可能會拋出一個受檢的異常,該變量就必須在try快內部進行初始化。
for循環的優劣
根據循環中循環變量的作用域和數目進行評價,因此 for循環優於while循環,foreach優於傳統for。
下面是遍歷的首先做法:
//適用與集合和數組
for(Element e: c){
doSomething(e);
}
在java 1.5版本之前的首先做法如下:
// 遍歷集合
for(Iterator i = c.iterator(); i.hasNext();){
doSomething((Element) i.next());
}
// 遍歷數組
for(int i = 0; i<a.length; i++){
doSomething(a[i]);
}
下面是另一種局部變量作用域最小化的循環做法:
// expensiveComputation()方法用於獲取n的數量,這樣做 局部變量i,n作用域只在for循環內。
for(int i = 0, n = expensiveComputation(); i <n ; i++){
doSomething(i);
}
有三種情況無法使用for-each循環
- 1.過濾 —- 如果需要遍歷集合,並刪除選定的元素,就需要使用顯示的迭代器,以便可以調用它的remove方法
- 2.轉換 —- 如果需要遍歷列表或者數組,並替換它全部或者部分元素值,就需要列表迭代或者數組索引,以便設定元素的值
- 3.平行迭代 —- 如果需要並行的遍歷多個集合,就需要顯示的控制迭代器或者索引變量,以便所有的迭代器或者索引變量都可以得到同步前移。
第49條:基本類型優於裝箱基本類型
java 1.5版本增加了自動裝箱和自動拆箱,他們之間主要有三個區別:
- 基本類型只有值,裝箱基本類型則具有與他們的值不同的同一性,換句話說,倆個裝箱基本類型可以具有相同的值和不同的同一性。
- 基本類型只有功能完備的值,而每個裝箱基本類型除了他對應基本類型的所有功能值以外,還有一個非功能值: null。
- 基本類型通常比裝箱基本類型更節省時間和空間。
考慮下面這個程序有什麼問題:
public static void main(String[] args){
Long sun = 0L;
for(long i = 0; i<100; i++){
sum += i;
}
System.out.println(sum);
}
這段代碼運行起來要比預想的慢很多,因爲它不小心把局部變量sum聲明爲裝箱基本類型Long。而不是基本類型long,這樣程序編譯起來沒有錯誤或者警告,變量被反覆的裝箱和拆箱,導致明顯的性能下降。
字符串的使用
如果其他類型更適合,要儘量避免使用字符串,字符串經常被錯誤的用來替代基本類型、枚舉類型、聚集類型。
字符串連接操作符( + )適用於: 產生單獨的一行輸出,或者構造一個字符串來表示一個較小的、大小固定的對象。但是如果是連接n個字符串,頻繁的使用字符串連接符,需要n的平方級的時間。這是因爲字符串不可變,當倆個字符串連接在一起時,他們的內容都要被拷貝。
考慮下面這段代碼:
public String statement(){
String result = "";
for(int i=0; i< numItems(); i++){
result += lineForItem(i); //String concatenation
}
return result;
}
如果項目數量巨大,這個方法的時間就難以估算。爲了獲得可以接受的性能,請使用StringBuilder代替String。(Java 1.5發行版本中增加了非同步StringBuilder類,代替現在過時的StringBuffer類)。
public String statement(){
StringBuilder b = new StringBuilder(numItems()*LINE_WIDTH);
for(int i = 0;i<numItems();i++){
b.append(lineForItem(i));
}
return b.toString();
}
第二種做法比第一張大約快85倍左右。