作者簡介:Joshua Bloch是Google的首席工程師,之前是Sun的杰出工程師,他領(lǐng)導(dǎo)了大量的java平臺設(shè)計(jì)和實(shí)現(xiàn)工作,包括jdk5.0的語言增強(qiáng)和集合框架,擁有卡內(nèi)基.梅隆大學(xué)的計(jì)算機(jī)科學(xué)的博士學(xué)位。
?
本書的目標(biāo)是幫助你最有效的運(yùn)用java編程語言及其基本庫,java.lang、java.util和java.io。本書由57個條目組成,每個條目傳達(dá)一個原則,這些原則是最有經(jīng)驗(yàn)的程序員在實(shí)踐過程中的一些有用的做法。
Creating and Destroying Object
?
Item 1:
考慮用靜態(tài)工廠方法替代構(gòu)造器
public static Boolean valueOf(boolean b) {
??? return (b?Boolean.TRUE:Boolean.FALSE);
}
考慮在構(gòu)造函數(shù)之外提供static的factory mothod。
優(yōu)點(diǎn):1.名字可不與類名相同,可以采用更易理解的名稱。2.不必每次都返回一個新的對象。3.可以返回子類型。
缺點(diǎn):1.無法被繼承。2.和其它static方法無法區(qū)分。
?
Item 2:
通過添加私有構(gòu)造器來加強(qiáng)單例屬性(singletom property)
public class Hello {
public static final Hello Instance = new Hell();
??? private Hello() {}???????????????????????????????????????
}
public class Hello {
private static final Hello Instance = new Hell();
??? private Hello(){}
??? public static Hello getInstance() {
???
????return Instance;
??? }
}
第二種方法可以方便改變。
如果想讓singleton類成為serializable,除了implements Serializable外,還要提供readResolve()方法返回該單例。
?
Item 3:
為構(gòu)造器添加private以避免被實(shí)例化
對于只是由static屬性和方法構(gòu)成的工具類,要為構(gòu)造器添加private,以免被實(shí)例化,而不添加的話,則可能有默認(rèn)的構(gòu)造器。
?
?
Item 4:
避免創(chuàng)建重復(fù)的對象
尤其是創(chuàng)建比較昂貴的。
對不可修改的對象盡量進(jìn)行復(fù)用,這樣效率和性能都會提高。例如如果循環(huán)100次String s = new String("hello")將創(chuàng)建100個對象 循環(huán)100次String s = "hello";則只創(chuàng)建了一個對象。很好的進(jìn)行了復(fù)用。
?
Item 5:
消除絕對的對象引用
內(nèi)存泄漏,在cache里易發(fā)生。
public Object pop(){
if(size == 0) {}??
?
??return elements[size--];
}
public Object pop() {
if(size == 0) {}
?
??Object obj = elements[--size];
?
??elements[size] = null;?
?
??return obj;
}
但是不要濫用,不要每個對象使用后都用NULL。
?
Item 6:
避免finalizer
不要當(dāng)作C++中的析構(gòu)函數(shù),正確的方法是放在finally中。
?
?
Methods Common to All Objects
?
Item 7:
當(dāng)你覆蓋equals方法的時候一定要遵守general contact
覆蓋equals的時候一定要加倍的小心,其實(shí)最好的辦法就是不覆蓋這個方法。比如在下面的情況下就可以不覆蓋
?? 1
這個類的每個實(shí)例都是唯一的,例如Thread類
?? 2
如果你不關(guān)心這個類是否該提供一個測試邏輯相等的方法
?? 3
超類已經(jīng)覆蓋了equals方法,并且它合適子類使用
?? 4
如果這個類是private或者是package-private的,并且你確信他不會被調(diào)用
覆蓋時遵守的原則是
必須與自身相等,對稱性A<->B,傳遞性,一致性如果不改變始終都是一致的結(jié)果,不能與NULL相等。
?
Item 8:
當(dāng)你覆蓋equals的時候必須覆蓋hashCode方法
不這么做的話,有關(guān)hash-based的集合操作會出錯。
契約:
同一對象的hashCode返回相同的結(jié)果(equals比較屬性沒改變),如果equals相等,則hashCode相等,如果equals不等,則hashCode不必不等。
?
?
Item 9:
總是覆蓋toString方法
Object
的toString方法返回的形式是Class的類型加上@加上16進(jìn)制的hashcode,不利于描述對象的信息。
?
Item 10:
謹(jǐn)慎覆蓋clone()方法
盡量不要實(shí)現(xiàn),碰到deepcopy的問題。
?
Item 11:
考慮實(shí)現(xiàn)覆蓋Comparable接口
?
契約:傳遞性,x.compareTo(y)>0,y.compareTo(z)>0,則x.compareTo(z)>0
如果x.compareTo(y)=0,則x.compareTo(z)和y.compareTo(z)結(jié)果一致
建議x.compareTo(y)=0 則 x.equals(y)=true,但不要求。
?
?
Classes and Interfaces
?
Item 12:
把類和成員的可訪問范圍降到最低
通常public類里不應(yīng)該有public字段,除了常量,要注意常量應(yīng)該是不可修改的。
public class Con {
public static final int[] data = {1,2,3};// it is bad
public static final String hello = "world";
public static final int i = 1;
}
?
Item 13:
偏愛不可修改的類
5
個原則保證不可修改
不提供可修改對象的方法,方法不可被覆蓋(final),所有字段是final,所有字段是private,確保外部不能訪問到類的可修改的組件
好處
可自由共享,線程安全
?
Item 14:
優(yōu)先考慮合成(復(fù)合),其次是繼承
利用wrapper class,除非確實(shí)是is a的關(guān)系。
?
?
Item 15:
如果要用繼承那么設(shè)計(jì)以及文檔都要有質(zhì)量保證,否則就不要用繼承
為了避免繼承帶來的問題,你必須提供精確的文檔來說明覆蓋相關(guān)方法可能出現(xiàn)的問題。
在構(gòu)造器內(nèi)千萬不要調(diào)用可以被覆蓋的方法
由于在Clone()或者序列化的時候非常類似構(gòu)造器的功能,因此readObject()和clone()方法內(nèi)最好也不要包括能被覆蓋的方法。
?
?
Item 16:
使用接口代替抽象類
單重繼承
?
Item 17:
接口只應(yīng)該用來定義類型
常量不應(yīng)該放在接口中。
?
Item 18:
優(yōu)先考慮靜態(tài)內(nèi)部類,而非非靜態(tài)內(nèi)部類
?
?
Substitutes for C Constructs
?
Item 19:
用類代替結(jié)構(gòu)
?
Item 20:
用類繼承來代替聯(lián)合
?
Item 21:
用類來代替enum結(jié)構(gòu)
?
Item 22:
用類和接口來代替函數(shù)指針
?
?
Methods
?
Item 23:
檢查參數(shù)的有效性
?
Item 24:
需要時使用保護(hù)性拷貝
?
Item 25:
謹(jǐn)慎設(shè)計(jì)方法的簽名
命名,不要過分提供便利的方法,避免過長參數(shù)列表
?
對于參數(shù)類型,優(yōu)先使用接口而不是類
謹(jǐn)慎的使用函數(shù)對象
?
Item 26:
謹(jǐn)慎的使用重載
?
Item 27:
返回零長度的數(shù)組而不是null
?
Item 28:
為所有導(dǎo)出的API元素編寫文檔注釋
當(dāng)代碼能很好的說明問題時,可不寫注釋
?
?
General Programming
?
Item 29:
將局部變量的作用域最小化
不易閱讀,在變量聲明的時候初始化,try-catch例外
for
循環(huán)優(yōu)于while循環(huán),for完全獨(dú)立,重用變量名不會有任何問題
for (int i=0,n=list.size(); i<n; i++) {
??? dosomething(list.get(i));
}
?
Item 30:
了解和使用庫
?
Item 31:
如果想要知道精確的答案,就要避免使用double和float
使用int,long或BigDecimal
?
Item 32:
如果其他類型更適合,則盡量避免使用字符串
如枚舉
?
Item 33:
了解字符串的連接功能
使用StringBuffer代替String
?
Item 34:
通過接口引用對象
參數(shù)、返回值,將會給函數(shù)帶來很大的靈活
?
Item 35:
接口優(yōu)先于反射機(jī)制
損失了編譯期的類型檢查的好處,性能上也會受損。
?
Item 36:
謹(jǐn)慎的使用本地方法
?
Item 37:
謹(jǐn)慎使用優(yōu)化
不要因?yàn)樾阅芏鵂奚侠淼拇a結(jié)構(gòu)
?
Item 38:
遵守普遍接受的命名慣例
?
?
Exceptions
?
Item 39:
僅在異常情況下使用異常
try {
int i=0;
while (true)
a[i++].f();
} catch (ArrayIndexOutOfBoundsException) {}
利用異常終止循環(huán),不要這樣濫用異常。
一個良好的設(shè)計(jì)不應(yīng)該依靠異常去控制流程
?
Item 40:
可恢復(fù)狀態(tài)使用檢查異常(Exception),對編程錯誤使用運(yùn)行期異常(RuntimeException)
?
Item 41:
避免不必要的使用檢查異常
可以先檢查是否有異常情況,而不是直接用try-catch控制程序流程
?
Item 42:
盡量使用標(biāo)準(zhǔn)異常
IllegalArgumentException
參數(shù)不合法,IllegalStateException狀態(tài)不合法
NullPointerException
空指針,IndexOutOfBoundsException越界
?
Item 43:
引發(fā)的異常要與抽象對應(yīng)
異常的分層,lower-level high-level
?
Item 44:
提供每個方法所拋出的異常的文檔
用javadoc的@throws標(biāo)簽
一般針對檢查異常
?
Item 45:
在messages中記錄失敗捕獲的信息
?
Item 46:
使失敗原子化
即使方法調(diào)用失敗后,也要恢復(fù)對象的狀態(tài)成為調(diào)用方法前的狀態(tài)
?
Item 47:
不要忽略異常
不要catch塊內(nèi)什么都不做
?
?
Threads
?
Item 48:
同步訪問共享可變的數(shù)據(jù)
private static int nextSerialNumber = 0;
//
需要同步
public static int generateSerialNumber() {
???? return nextSerialNumber++;
}
public class StoppableThread extends Thread {
???? private boolean stopRequested = false;
???? public void run() {
???????? boolean done = false;
???????? while (!stopRequested() && !done) {
????????????? //dosth
???????? }
???? }
???? //
需要同步
???? public synchronized void requestStop() {
???????? stopRequested = true;
???? }
???? private synchronized boolean stopRequested() {
???????? return stopRequested;
???? }
}
?
Item 49:
避免過度使用同步
性能的下降
在同步塊里盡可能少的操作
?
Item 50:
不要在循環(huán)外部調(diào)用wait
一般習(xí)慣的方法
synchronized (obj) {
???? while (<condition does not hold>)
???????? obj.wait();
???? //Perform action appropriate to condition
}
?
Item 51:
不要依賴線程調(diào)度器
?
Item 52:
文檔化線程安全
如果一個類支持線程安全的話,一定要文檔說明
?
Item 53:
避免使用線程組
?
?
Serialization
?
Item 54:
謹(jǐn)慎實(shí)現(xiàn)Serializable
表面簡單implements Serializable,實(shí)際上復(fù)雜
如果實(shí)現(xiàn)了,那私有或包私有的屬性也會成為exported API的一部分,違背了隱藏內(nèi)部實(shí)施細(xì)節(jié)的原則。
serialVersionUID
屬性,如果代碼中不指定的話,系統(tǒng)會根據(jù)類名,實(shí)現(xiàn)接口名,成員名稱,生成一個
即使添加一個很普通的方法,也會改變該值,這樣就失去兼容性。
?
Item 55:
考慮使用自定義的序列化格式
覆蓋writeObject()和readObject()
?
Item 56:
保護(hù)性地編寫readObject方法
存在安全漏洞,反序列化
?
Item 57:
必要時提供readResolve方法