實踐:實際履行, 尤指藝術(shù). 科學或技術(shù)領(lǐng)域:與理論遙相對應(yīng).
Praxis: Practice,especially of an art,science, or technical occupation, opposite to theory.
-Webster''s New Collegiate Dictionary 1958
譯序by侯捷
譯序by劉永丹
細目 DetailContents
前言preface
致謝 Acknowledgement
1 一般技術(shù)(General Techniques)
實踐1:參數(shù)以byvalue方式而非by reference方式傳遞
實踐2:對不變的data和object reference使用final
實踐3:缺省情況下所有non-static函數(shù)都可被覆寫
實踐4:在arrays和vectors之間慎重選擇
實踐5:多態(tài) po1ymorphism 優(yōu)于instanceof
實踐6:必要時才使用instanceof
實踐7:一旦不再需要objectreferences, 就將它設(shè)為nu11
2 對象與相等性(Objects and Equality)
實踐8:區(qū)分reference型別和primitive型別
實踐9:區(qū)分==和equals
實踐10:不要依賴equals 的缺省實現(xiàn)
實踐11:實現(xiàn)equals 時必須深思熟慮
實踐12:實現(xiàn)equals 時優(yōu)先考慮使用getClass
實踐13:調(diào)用super. equals 以喚起baseclass的相關(guān)行為
實踐14:在equals 函數(shù)中謹慎使用instanceof
實踐15:實現(xiàn)equals 時需遵循某些規(guī)則
3異常處理(Exception Handling)
實踐16:認識[異??刂屏鱙 exceptioncontrolflow 機制
實踐17:絕對不可輕忽異常 Neverignoreanexception
實踐18:千萬不要遮掩異常 Neverhideanexception
實踐19:明察throws子句的缺點
實踐20:細致而全面地理解throws子句
實踐21:使用finally避免資源泄漏 resourceleaks
實踐22:不要從try區(qū)段中返回
實踐23:將try/catch區(qū)段置于循環(huán)之外
實踐24:不要將異常 exceptions 用于流程控制
實踐25:不要每逢出錯就使用異常 exceptions
實踐26:在構(gòu)造函數(shù) constructors 中拋出異常
實踐27:拋出異常之前先將對象恢復(fù)為有效狀態(tài) valid state
4 性能(Performance)
實踐28:先把焦點放在設(shè)計. 數(shù)據(jù)結(jié)構(gòu)和算法身上
實踐29:不要倚賴編譯期 compile-time 優(yōu)化技術(shù)
實踐30:理解運行期 mntime 代碼優(yōu)化技術(shù)
實踐31:如欲進行字符串接合, StringBuffer優(yōu)于String
實踐32:將對象的創(chuàng)建成本 creationcost 降至最小
實踐33:慎防未用上的對象 unusedobjects
實踐34:將同步化 synchronization 降至最低
實踐35:盡可能使用stack變量
實踐36: 使用static. final和private函數(shù)以促成inlining
實踐37:instance變量的初始化一次就好
實踐38:使用基本型別 primitivetypes 使代碼更快更小
實踐39:不要使用Enumeration或Iterator來遍歷vector
實踐40:使用System. arraycopy 來復(fù)制arrays
實踐41:優(yōu)先使用array, 然后才考慮Vector和ArrayList
實踐42:盡可能復(fù)用 reuse 對象
實踐43:使用緩式評估 延遲求值, lazyevaluation
實踐44:以手工方式將代碼優(yōu)化
實踐45:編譯為本機代碼 Compile to native code
5 多線程 Multithreading
實踐46:面對instance函數(shù), synchronized鎖定的是對象 objects 而非函數(shù) methods 或代碼 code
實踐47:弄清楚synchronizedstatics函數(shù)與synchronized instance函數(shù)之間的差異
實踐48:以[private數(shù)據(jù)十相應(yīng)訪問函數(shù) accessor ]替換[public/protected數(shù)據(jù)]
實踐49:避免無謂的同步控制
實踐50:訪問共享變量時請使用synchronized或volatile
實踐51:在單一操作 singleoperation 中鎖定所有用到的對象
實踐52:以固定而全局性的順序取得多個locks 機鎖 以避免死鎖
實踐53:優(yōu)先使用notifyAll 而非notify
實踐54:針對wait 和notifyAll 使用旋鎖 spinlocks
實踐55:使用wait 和notifyAll 替換輪詢循環(huán) pollingloops
實踐56:不要對locked object 上鎖對象 之object reference重新賦值
實踐57:不要調(diào)用stop 或suspend
實踐58:通過線程 threads 之間的協(xié)作來中止線程
6 類與接口(Classes and Interfaces)
實踐59:運用interfaces支持多重繼承 multipleinheritance
實踐60:避免interfaces中的函數(shù)發(fā)生沖突
實踐61:如需提供部分實現(xiàn) partial implementation 請使用abstract classes 抽象類
實踐62:區(qū)分interface. abstractclass和concreteclass
實踐63:審慎地定義和實現(xiàn)immutableclasses 不可變類
實踐64:欲傳遞或接收mutableobjects 可變對象 之objectreferences時, 請實施clone
實踐65:使用繼承 inheritance 或委托 delegation 來定義immutableclasses 不可變類
實踐66: 實現(xiàn)clone 時記得調(diào)用super. clone
實踐67:別只依賴finalize 清理non-memory 內(nèi)存以外 的資源
實踐68:在構(gòu)造函數(shù)內(nèi)調(diào)用non-final函數(shù)時要當心
附錄:如何學習Java
進階讀物 Further Reading
索引 Index
一般技術(shù)(General Techniques)
實踐1:引數(shù)是以傳值(by value)而非傳址(by reference)方式傳遞
所有Java objects都透過object reference而被取用. 常見的一個誤解是Java以by reference方式傳遞引數(shù). 事實上所有引數(shù)都以by value方式傳遞.
實踐2:對不變的data和object reference使用final
為了讓data或object reference成為不變量, 請使用final. 注意, final僅僅令object reference自身成為不變量, 并不限制它所指向之物件的改變.
實踐3:預(yù)設(shè)情況下所有non-static函式都可被覆寫(overridden)
預(yù)設(shè)情況下, 所有non-static函式都可以被subclass覆寫. 但如果加上關(guān)鍵字final, 便可防止被subclass覆寫.
實踐4:慎重選擇arrays和Vectors
arrays和vectors是常見的容器類別(storage classes). 選用它們之前應(yīng)該先了解它們的功用和特性.
實踐5:多型(polymorphism)優(yōu)於instanceof
instanceof的許多用途可以因為改用多型而消除之. 使用多型, 程式碼將更清晰. 更易於擴展和維護.
實踐6:必要時才使用instanceof
有時我們無法回避使用instanceof. 我們應(yīng)該了解什麼情況下必須使用它.
實踐7:一旦不再需要object references, 就將它設(shè)為null
不要忽視記憶體可能帶來的問題. 盡管有了垃圾回收機制(garbage collection), 你仍然需要關(guān)注你的程式碼如何運用記憶體. 如果能夠領(lǐng)悟垃圾回收機制和記憶體運用細節(jié), 你就能夠更好地知道何時應(yīng)該將object references設(shè)為null, 那將導(dǎo)致高效的程式碼.
物件與相等性(Objects and Equality)
實踐8:區(qū)分reference type和primitive type
Java是物件導(dǎo)向的, 但其操控的東西并非都是物件(objects). 理解reference type和primitive types之間的差異, 及它們在JVM中的表述(representation), 會使你在運用它們時得以做出明智的選擇.
實踐9:區(qū)分 == 和equals
== 用來測試基本型別的相等性, 亦可判定兩個object references是否指向同一個object. 若要測試values(值)或semantic(語意)相等, 應(yīng)使用equals .
實踐10:不要依賴equals 的預(yù)設(shè)實作(default implementation)
不要不假思索地認定一個class總是會正確實作出equals . 此外, java.lang.Object提供的equals 大多數(shù)時候并非進行你想要的比較.
實踐11:實作equals 時必須深思熟慮
如果某個class的兩個objects「即使不占用相同的記憶體空間, 也被視為邏輯上相等」, 那麼就該為這個class提供一個equals .
實踐12:實作equals 時優(yōu)先考慮使用getClass
實作equals 時請優(yōu)先考慮采用getClass . 畢竟, 「相同class下的objects才得被視為相等」是正確實作equals 的一個清晰簡明的解決方案.
實踐13:呼叫base class(基礎(chǔ)類別)的super.equals
任何base class(除了java.lang.Object)如果實作equals , 其derived class都應(yīng)該呼叫super.equals .
實踐14:在equals 函式中謹慎使用instanceof
唯有當你考慮允許「一個derived class object可以相等於其base class object」時, 才在equals 中使用instanceof. 使用這項技術(shù)前請先弄清楚其影響.
實踐15:實作equals 時需遵循某些規(guī)則
撰寫equals 并非那麼直觀淺白. 如果想要恰當?shù)貙嵶鞒鰁quals , 請遵循某些規(guī)則.
異常處理(Exception Handling)
實踐16:認識「異??刂屏鳌梗╡xception control flow)機制
讓自己諳曉異??刂屏鞒碳毠?jié). 了解這些細微之處有助於你回避問題.
實踐17:絕對不可輕忽異常(Never ignore an Exceptions)
一旦異常出現(xiàn)卻沒有被捕獲, 拋出異常的那個執(zhí)行緒(thread)就會中止運行. 是的, 異常意味錯誤, 永遠不要忽略它.
實踐18:千萬不要掩蓋異常(Never hide an Exceptions)
如果處理異常期間又從catch或finally區(qū)段拋出異常, 原先的異常會因而被隱蔽起來. 一旦發(fā)生這樣的事情, 就會丟失錯誤資訊. 你應(yīng)當撰寫專門負責處理這種情形的程式碼, 將所有異常回傳給呼叫者.
實踐19:明察throws子句的缺點
將一個異常加入某函式的throws子句, 會影響該函式的所有呼叫者.
實踐20:細致而全面地理解throws子句
任何函式的throws子句應(yīng)當列出它所傳播的所有異常, 包括衍生異常型別(derived exception types).
實踐21:使用finally避免資源泄漏(resource leaks)
不要忽視記憶體以外的資源. 垃圾回收機制不會替你釋放它們. 請使用finally確保記憶體以外的資源被釋放.
實踐22:不要從try區(qū)塊中回返
不要從try區(qū)塊中發(fā)出return指令, 因為這個函式未必會立即從那兒回返. 如果存在finally區(qū)段, 它就會被執(zhí)行起來并可能改變回傳值.
實踐23:將try/catch區(qū)塊置於回圈(loop)之外
撰寫含有異常處理的回圈時, 請將try和catch區(qū)塊置於回圈外部. 在某些實作版本上, 這會產(chǎn)生更快的執(zhí)行碼.
實踐24:不要將異常(exceptions)用於流程控制
請將異常用於預(yù)期行為之外的情況. 不要以異常來控制流程, 請采用標準的語言流程構(gòu)件(flow constructs), 這樣的流程表達會更清晰更高效.
實踐25:不要每逢出錯就使用異常(exceptions)
只有面對程式行為可能出乎預(yù)料的情境下才使用異常. 「預(yù)期中的行為」應(yīng)使用回傳碼(return codes)來處理.
實踐26:在建構(gòu)式(constructors)中拋出異常
盡管建構(gòu)式并非函式(method), 因而不能回傳一個值, 但建構(gòu)式有可能失敗. 如果它們失敗了, 請拋出一個異常.
實踐27:拋出異常(exceptions)之前先將object恢復(fù)為有效狀態(tài)
拋出異常很容易, 困難的是「將異常所引發(fā)的傷害減到最小」. 拋出異常之前, 應(yīng)確?!溉绻惓1惶幚砗? 流程再次進入拋出異常的那個函式中, 該函式可以成功完成」.
效能/效率(Performance)
實踐28:先把焦點放在設(shè)計. 資料結(jié)構(gòu)和演算法身上
給Java帶來最大效能提升的辦法就是:在設(shè)計和演算法中使用與語言無關(guān)的技術(shù). 因此, 首先請將你的精力集中於這些上面.
實踐29:不要倚賴編譯期程式碼優(yōu)化技術(shù)
由Java編譯器生成的碼, 通常不會比你自己撰寫的更好. 別指望編譯器能夠多麼優(yōu)化你的原始碼.
實踐30:理解運行期(runtime)程式碼優(yōu)化技術(shù)
Java效能的大部分努力都圍繞著運行期優(yōu)化展開. 這種作法有利有弊.
實踐31:如欲進行字串接合, StringBuffer優(yōu)於String
對於字串接合, StringBuffer class要比String class快許多倍.
實踐32:將object的創(chuàng)建成本(creation cost)降至最小
在許多物件導(dǎo)向系統(tǒng)中, 「產(chǎn)生物件」意味著高昂的成本. 了解成本所在, 以及了解「加速物件產(chǎn)生速度」的技術(shù), 都可以導(dǎo)致更快的程式碼.
實踐33:慎防未用上的物件(unused objects)
非必要別產(chǎn)生物件. 非必要地產(chǎn)生物件, 會減慢你的程式速度.
實踐34:將同步(synchronization)減至最低
宣告synchronized函式或synchronized區(qū)塊, 會顯著降低效能. 只在物件需要時才使用同步機制(synchronization).
實踐35:盡可能使用stack變數(shù)
stack變數(shù)為JVM提供了更高效的byte code指令序列. 所以在回圈內(nèi)重復(fù)取用static變數(shù)或instance變數(shù)時, 應(yīng)當將它們臨時儲存於stack變數(shù)中, 以便獲得更快的執(zhí)行速度.
實踐36:使用static. final和private函式以允許實施inlining
以函式本體替換函式呼叫, 會導(dǎo)致更快的程式碼. 如果要令函式為inline, 必須先宣告它們?yōu)閟tatic. final或private.
實踐37:instance變數(shù)的初始化只要一次就好
由於所有static變數(shù)和instance變數(shù)都會自動獲得預(yù)設(shè)值, 所以不必重新將它們設(shè)為預(yù)設(shè)值.
實踐38:使用基本型別(primitive types)使程式碼更快更小
使用基本型別, 比使用基本型別外覆類別(wrapper), 產(chǎn)生的程式碼又小又快.
實踐39:不要使用Enumeration或Iterator來巡訪Vector
巡訪Vector時, 請使用get函式而非Enumeration或Iterator. 這樣做會導(dǎo)致更少的函式呼叫, 意味程式碼會更快.
實踐40:使用System.arraycopy
來復(fù)制arrays
請使用System.arraycopy
來復(fù)制arrays. 那是個原生(native)函式, 速度最快.
實踐41:優(yōu)先使用array, 然後才考慮Vector和ArrayList
如果可能, 就使用array. 如果你需要Vector的功能但不需要它的同步特性, 可改用ArrayList.
實踐42:盡可能復(fù)用(reuse)objects
復(fù)用現(xiàn)有物件, 幾乎總是比產(chǎn)生新物件更劃算.
實踐43:使用緩式評估(延遲求值, lazy evaluation)
如果某個成本高貴的計算并非一定必要, 就盡量少做. 請使用「緩式評估」
(lazy evaluation, 延遲求值)技術(shù)避免那些永遠不需要的工作.
實踐44:手工優(yōu)化(optimize)你的程式碼
由於Java編譯器在優(yōu)化方面的作為甚少, 為了生成最佳byte code, 請手工優(yōu)化你的原始碼.
實踐45:編譯為原生碼(native code)
編譯為原生碼, 通常可以導(dǎo)致執(zhí)行速度更快的程式碼. 但你卻因此必須在各種不同的原生方案(native solution)中取舍.
多緒(Multithreading)
實踐46:面對instance函式, synchronized鎖定的是物件而非函式或程式碼
關(guān)鍵字synchronized鎖定的是物件, 而非函式或程式碼. 一個函式或程式
區(qū)段被宣告為synchronized, 并不意味同一時刻只能由一個執(zhí)行緒執(zhí)行它.
實踐47:弄清楚synchronized statics與synchronized instance函式之間的差異
兩個函式被宣告為synchronized, 并不就意味它們是「執(zhí)行緒安全」(thread-safe)的. 對instance函式或object reference同步化, 與對static函式或class literal(字面常數(shù))同步化相比, 得到的lock全然不同
實踐48:以「private資料搭配存取器(accessor)」取代public/protected資料
如果沒有適當保護你的資料, 用戶便有機會繞過你的同步機制.
實踐49:避免無謂的同步控制(avoid unnecessary synchronization)
一般情況下請不要同步化所有函式. 同步化不僅造成程式緩慢, 并且喪失了
并行(concurrency)的可能. 請采用「單物件多鎖」技術(shù)以允許更多并行.
實踐50:取用共享變數(shù)時請使用synchronized或volatile
不可切割(原子化, atomic)操作并非意味「執(zhí)行緒安全」. JVM實作品被允許在私有記憶體中保留變數(shù)的工作副本. 這可能會產(chǎn)生陳舊數(shù)值(stale values). 為避免這個問題, 請使用同步化機制或?qū)⒆償?shù)宣告為volatile.
實踐51:在單一操作(single operation)中鎖定所有用到的objects
同步化某一函式, 并不一定就會使其成為「執(zhí)行緒安全」的函式碼. 如果synchronized函式操控著多個objects, 而它們并不都是此函式所屬class的private instance data, 那麼你必須對這些objects自身也進行同步化.
實踐52:以固定而全域性的順序取得多個locks(機鎖)以避免死結(jié)(deadlock)
當你同步化多個物件, 請以固定和全域性的順序獲得locks, 以避免死結(jié).
實踐53:優(yōu)先使用notifyAll 而非notify
notify 只喚醒一個執(zhí)行緒. 要想喚醒多個執(zhí)行緒, 請使用notifyAll .
實踐54:針對wait 和notifyAll 使用旋鎖(spin locks)
當你等待條件變數(shù)(condition variables)時, 請總是使用旋鎖(spin locks)以確保正確結(jié)果.
實踐55:使用wait 和notifyAll 取代輪詢回圈(polling loops)
將所有polling loops替換為使用wait . notify 和notifyAll 的spin locks(旋鎖). 使用spin locks直觀而高效, 使用polling loops則慢很多倍.
實踐56:不要對locked object(上鎖物件)之object reference重新賦值
當一個object被鎖定, 有可能其他執(zhí)行緒會因同一個object lock而受阻(blocked). 假如你對上鎖物件的object reference重新賦值, 其他執(zhí)行緒中懸而未決的那些locks將不再有意義.
實踐57:不要呼叫stop 或suspend
不要呼叫stop 或suspend , 因為它們可能導(dǎo)致資料內(nèi)部混亂, 甚至引發(fā)死結(jié)(deadlock).
實踐58:透過執(zhí)行緒(threads)之間的合作來中止執(zhí)行緒
你不應(yīng)該呼叫stop . 如欲安全地停止執(zhí)行緒, 必須要求它們相互協(xié)作, 才能姿態(tài)優(yōu)雅地中止.
類別與介面(Classes and Interfaces)
實踐59:使用interface支援多重繼承(multiple inheritance)
當你想要支援interface的單一繼承或多重繼承, 或者想要實作一個標記式的(marker)interface時, 請使用interfaces.
實踐60:避免interfaces中的函式發(fā)生沖突
沒有任何辦法能夠阻止兩個interfaces使用同名的常數(shù)和函式. 為了避免可能的沖突, 應(yīng)當小心命名常數(shù)和函式.
實踐61:需要提供部分實作(partial implementation)時, 請使用abstract classes
使用abstract class來為一個class提供部分實作, 這些實作很可能對derived class是共通的(都被需要的).
實踐62:區(qū)分interface. abstract class和concrete class
一旦正確理解了interface. abstract class和concrete class的差異, 你就可以在設(shè)計和撰碼時做出正確的選擇.
實踐63:審慎地定義和實作immutable classes(恒常類別)
如果你希望object的資料永遠不被改動, 請使用immutable object. 這種objects自動擁有執(zhí)行緒安全性(thread safety).
實踐64:欲傳遞或接收mutable objects(可變物件)之object references時, 請施行clone
為了保證immutable objects, 你必須在傳入和回傳immutable objects時對它們進行clone動作.
實踐65:使用繼承(inheritance)或委托(delegation)來定義 immutable classes(恒常類別)
使用immutable interface. common interface或base class, 或是immutable delegation classes, 來定義immutable classes(恒常類別).
實踐66:實作clone 時記得呼叫super.clone
當你實作了一個clone , 總是應(yīng)該呼叫super.clone 以確保產(chǎn)生正確的object.
實踐67:別只是倚賴finalize 清理記憶體以外的(non-memory)資源
你不能保證finalize 是否被呼叫, 以及何時被呼叫. 因此, 請專門實作一個public函式來釋放記憶體以外的資源.
實踐68:在建構(gòu)式(constructors)內(nèi)呼叫non-final函式時要當心
如果一個non-final函式被某個derived class覆寫, 在建構(gòu)式中呼叫這個函式可能會導(dǎo)致不可預(yù)期的結(jié)果.