posts - 11, comments - 10, trackbacks - 0, articles - 0
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          Practical Java讀書筆記

          Posted on 2006-08-30 17:50 繁星滿空 閱讀(496) 評論(0)  編輯  收藏 所屬分類: Java

          作者簡介:Peter HaggarIBM在北卡羅來納州的Research Triangle Park的一名高級軟件工程師,他發表了無數篇關于 Java 編程的文章。他有著廣泛的編程經驗,曾致力于開發工具、類庫和操作系統的相關工作。Peter IBM從事新興因特網技術方面的工作,目前主要從事有關高性能Web服務方面的工作。Peter經常在很多業界會議上作為技術發言人就 Java 技術發表言論。他已經為IBM工作了15年多,并獲得了Clarkson University的計算機科學學士學位。

          ?

          本書匯集了Java編程實踐方面的建議、忠告、范例和討論,本書的組織是一個個獨立的課程,每個課程稱為實踐(PRAXIS),用以討論特定主題,每個實踐按各自獨立的方式撰寫。本身詳細分析了某些設計和編程方面的問題,挑選的依據是編程實踐上的有效和高效。Java最被人抱怨的一點是性能,因此本書以最大的篇幅討論這一主題,使Java代碼運行得更高效。


          General Techniques


          ?

          PRAXIS1: 引數以by value方式而非by reference方式傳遞

          所有Java對象都通過object reference被訪問,常見的一個誤解是javaby reference方式傳遞引數,

          事實上所有引數都以by value方式傳遞。

          ?

          比如int參數,在函數內修改了,在調用后并沒有修改

          object則不是這樣,函數內修改了,調用后也是修改的,若不想這樣,可以把object改為不可變的或拷貝object

          ?

          PRAXIS2: 對不變的dataobject references使用final

          為了讓dataobject reference成為不變量(常數),請使用final。注意,final僅僅令object reference

          自身成為不變量,并不限制它所指對象的改變。

          ?

          PRAXIS3: 缺省情況下所有non-static函數都可被覆蓋

          缺省情況下,所以non-static函數都可以被subclass覆蓋,但如果加上關鍵字final,便可防止被subclass覆蓋。

          聲明某個類為final,就表示這個類的所有函數都是final的,可以阻止它派生子類。

          ?

          PRAXIS4: arraysVectors之間慎重選擇

          arrays vectors是常見的容器類(storage classes)。選用它們之前應該先了解它們的功用和特性。

          ?

          如果超出了array的大小,會報數組越界異常,基本類型的array會自動為數組內的元素賦默認值,而對象數組則是null。而vector長度會自動增長,vector.size()返回的元素的數量,不是固定值,vector的內部實現是array實現的,vector只能容納對象。

          一般來說,array速度更快。

          ?

          PRAXIS5: 多態優于instanceof

          instanceof 的許多用途可以因為改用多態而消失,使用多態,代碼將更清晰、更易于擴展和維護。

          ?

          PRAXIS6: 必要時才使用instanceof

          有時我們無法回避使用instanceof。我們應該了解什么情況下必須使用它。

          ?

          PRAXIS7: 一旦不再需要object references,就將它設為null

          不要忽視內存可能帶來的問題,盡管有了垃圾回收機制,你仍然需要關注你的代碼如何運用內存,如果能夠領悟垃圾回收和內存運用細節,你就能夠更好的知道何時應該將object references設為null,那將導致高效的代碼。



          Objects and Equality


          ?

          PRAXIS8: 區分reference typeprimitive type

          Java 是面向對象語言,但其操控的東西并非都是對象(objects)。理解reference typeprimitive types之間的差異,及它們在JVM中的表述,會使你在運用它們時得以做出明智的選擇。

          ?

          PRAXIS9: 區分==equals()

          == 用來測試基本型別的相等性,亦可判定兩個object references是否指向同一個對象,但若要測試

          values (值)或semantic(語義)相等,應使用equals()

          ?

          PRAXIS10: 不要依賴equals()的缺省實現

          不要不假思索的認定一個class總是會正確的實現出equals(),此外,java.lang.Object提供的equals()大多數時候并非進行你想要的比較。

          ?

          PRAXIS11: 實現equals()時必須深思熟慮

          如果某個class所生的兩個對象“即使不占用相同的內存空間,也被視為邏輯上相等”,那么就該為這個class提供一個equals()。

          ?

          PRAXIS12: 實現equals()時優先考慮使用getClass()

          實現equals()時請優先考慮采用getClass()。畢竟,“隸屬同一個class下的對象才得被視為相等”是正確實現equals()的一個簡明方案。

          ?

          惟有相同class所產生的對象才可以被視為相等,可以只比較某些關鍵屬性。

          ?

          PRAXIS13: 調用super.equals()以喚起base class的相關行為

          任何base class(除了java.lang.Object)如果實現equals(),其derived class都應該調用super.equals()。

          ?

          PRAXIS14: equals()函數中謹慎使用instanceof

          惟有當你考慮允許“一個derived class對象可以相等于其base class對象”時,才在equals()中使用instanceof。使用這項技術前請先弄清楚其影響。

          ?

          PRAXIS15: 實現equals()時需遵循某些規則

          撰寫equals()并非那么直觀,如果想要恰當實現出equals(),請遵循某些規則。

          ?

          1. 如果某個class的兩個對象即使占據不同的內存空間,也可被視為“邏輯上相等”的話,那么你得為這個class提供一個equals()

          2. 請檢查是否等于this。

          3. 比較這個class中的相關屬性,以判斷兩個對象是否相等。

          4. 如果有java.lang.Object以外的任何base class實現了equals(),那么就應該調用super.equals()




          Exception Handling


          ?

          PRAXIS16: 認識“異??刂屏鳌保?span lang="EN-US">exception control flow)機制

          了解異??刂屏鞒碳毠?,了解這些細微之處有助于你回避問題。

          ?

          PRAXIS17: 不要忽略異常

          一旦異常出現卻沒有被捕獲,拋出異常的那個線程就會中止運行,是的,異常意味錯誤,永遠不要忽略它。

          ?

          PRAXIS18: 不要隱藏異常

          如果處理異常期間又從catchfinally區段拋出異常,原先的異常會因而被隱藏起來,一旦發生這樣的事情,就會丟失錯誤信息,你應當撰寫專門負責處理這種情形的代碼,將所有異?;貍鹘o調用者。

          ?

          只有一個異??梢詡鞑サ酵饨?,可以把所有的異常加入到一個vector內。

          ?

          PRAXIS19: 理解throws子句的缺點

          將一個異常加入某函數的throws子句,會影響該函數的所有調用者。

          ?

          PRAXIS20: 細致而全面的理解throws子句

          任何函數的throws子句應當列出它所傳播的所有異常,包括衍生異常型別(derived exception types)。

          ?

          覆蓋一個方法時,throws的異常受到約束

          要么不拋出異常,要么和被覆蓋方法一樣類型的異常,要么是被覆蓋方法異常的派生異常。

          ?

          PRAXIS21: 使用finally避免資源泄漏

          不要忽視內存以外的資源,垃圾回收機制不會替你釋放它們,請使用finally確保內存以外的資源被釋放。

          ?

          PRAXIS22: 不要從try塊中返回

          不要從try區段中發出return語句,因為這個函數未必會立即從那兒返回,如果存在finally區段,它就會被運行起來并可能改變回傳值。

          ?

          PRAXIS23: try/catch代碼塊置于循環外

          撰寫含有異常處理的循環時,請將trycatch區段置于循環外部,在某些實現版本上,這會產生更快的運行代碼。

          ?

          PRAXIS24: 不要將異常用于流程控制

          請將異常用于預期行為之外的情況,不要以異常來控制流程,請采用標準的語言流程構件,這樣的流程表達會更清晰更高效。

          ?

          PRAXIS25: 不要每逢出錯就使用異常

          只有面對程序行為可能出乎意料的情況下才使用異常,“預期中的行為”應使用返回代碼來處理。

          ?

          PRAXIS26: 在構造函數中拋出異常

          盡管構造函數并非函數(method),因而不能回傳一個值,但構造函數有可能失敗,如果它們失敗了,請拋出一個異常。

          ?

          PRAXIS27: 拋出異常之前先將對象恢復為有效狀態(valid state

          拋出異常很容易,困難的是“將異常所引發的傷害減到最小”,拋出異常前,應確保“如果異常被處理好,流程再次進入拋出異常的那個函數中,該函數可以成功完成”。




          Performance


          ?

          PRAXIS28: 先把焦點放在設計、數據結構和算法身上

          java帶來最大性能提升的辦法就是:在設計和算法中使用與語言無關的技術,因此,首先請將你的精力集中在這上面。

          ?

          PRAXIS29: 不要依賴編譯期的優化技術

          java編譯器生成的代碼,通常不會比你自己撰寫的更好,別指望編譯器能夠多么優化你的源碼。

          ?

          PRAXIS30: 理解運行期的代碼優化技術

          Java 對性能的大部分努力都圍繞著“運行期優化”展開,這種做法有利無弊。

          ?

          PRAXIS31: 如欲進行字符串的連接,StringBuffer優于String

          對于字符串的連接,StringBuffer要比String快許多倍。

          ?

          PRAXIS32: 將對象的創建成本降至最小

          在許多面向對象系統中,“創建對象”意味著高昂的成本,了解成本所在,以及了解“加速對象創建速度”的技術,都可以導致更快速的程序。

          ?

          PRAXIS33: 謹防未使用的對象

          非必要別產生對象,否則會減慢你的程序速度。

          ?

          PRAXIS34: 將同步(synchronization)減至最低

          聲明synchronized函數或synchronized區段,會顯著降低性能,應該只在對象有所需要時才使用同步機制。

          ?

          PRAXIS35: 盡可能使用stack變量

          stack 變量為JVM提供了更高效的byte code指令序列,所以在循環內重復訪問static變量或instance變量時,應當將它們暫時存儲于stack變量中,以便獲得更快的運行速度。

          ?

          PRAXIS36: 使用static、finalprivate函數以促成inlining

          以方法體替換方法調用,會導致更快速的程序,如果要令函數為inline,必須先聲明它們為static、finalprivate。

          ?

          PRAXIS37:instance 變量的初始化一次就好

          由于所有static變量和instance變量都會自動獲得缺省值,所以不必重新將它們設為缺省值。

          ?

          PRAXIS38: 使用基本類型(primitive types)使代碼更快更小

          使用基本類型,比使用其包裝類,產生的代碼又小又快。

          ?

          PRAXIS39: 不要使用EnumerationIterator來遍歷Vector

          遍歷Vector時,請使用get()函數而非EnumerationIterator。這樣做會導致更少的函數調用,意味程序速度更快。

          ?

          PRAXIS40: 使用System.arraycopy()來復制arrays

          這個是本機(native)函數,速度更快。

          ?

          PRAXIS41: 優先使用array,然后才考慮VectorArrayList

          如果你需要Vector的功能但不需要它的同步特性,可改用ArrayList。

          ?

          PRAXIS42: 盡可能復用(reuse)對象

          復用現有對象,幾乎總是比創建新對象更劃算。

          ?

          PRAXIS43: 使用延遲求值(lazy evaluation

          如果某個成本高貴的計算并非一定必要,就盡量少做,使用懶加載技術避免那些永遠不需要的工作。

          ?

          PRAXIS44: 以手工方式將代碼優化

          由于Java編譯器在優化方面的作為甚少,為了生成最佳byte code,請以手工方式將你的源碼優化。

          ?

          PRAXIS45: 編譯為本機代碼(native code

          編譯為本機代碼,通常可以獲得運行速度更快的代碼,但你卻因此必須在各種不同的本機方案中取舍。

          ?



          Multithreading


          ?

          PRAXIS46: 面對instance函數,synchronized鎖定的是對象(object)而非函數(method)或代碼

          關鍵字synchronized鎖定的是對象,而非函數或代碼,一個函數或程序區段被聲明為synchronized,并不意味同一時刻只能由一個線程運行它。

          ?

          PRAXIS47: 弄清楚synchronized statics函數與synchronized instance函數之間的差異

          兩個函數被聲明為synchronized,并不就意味它們是“多線程安全”,對instance函數或object reference同步化,與對static函數或class literal(字面常數)同步化相比,得到的lock全然不同。

          ?

          PRAXIS48: private數據(field+相應的訪問函數(accessor)替換public/protected數據

          如果沒有適當保護你的數據,用戶便有機會繞過你的同步機制。

          ?

          PRAXIS49: 避免無謂的同步控制

          一般情況下請不要同步化所有函數,同步化不僅造成程序緩慢,并且喪失了并發(concurrency)的可能,

          請采用“單對象多鎖”技術以允許更多并發動作。

          ?

          PRAXIS50: 訪問共享變量時請使用synchronizedvolatile

          不可切割(原子化,atomic)操作并非意味“多線程安全”,JVM實現品被允許在私有內存中保留變量的工作副本,這可能會產生陳舊數據,為避免這個問題,請使用同步化機制或將變量聲明為volatile

          ?

          PRAXIS51: 在單一操作中鎖定所有用到的對象

          同步化某一函數,并不一定就會使其成為“多線程安全”,如果synchronized函數操控著多個函數,而它們并不都是此函數所屬classprivate instance data,那么你必須對這些對象自身也進行同步化。

          ?

          PRAXIS52: 以固定而全局性的順序取得多個locks,以避免死鎖(deadlock

          當你同步化多個對象,請以固定、全局性的順序獲得locks,以避免死鎖。

          ?

          PRAXIS53: 優先使用notifyAll()而非notify()

          notify() 只喚醒一個線程,要想喚醒多個線程,請使用notifyAll()

          ?

          PRAXIS54: 針對wait()notifyAll()使用旋鎖(spin locks

          當你等待條件變量時,請總是使用旋鎖確保正確結果。

          ?

          PRAXIS55: 使用wait()notifyAll()替換輪詢循環(polling loops

          將所有polling loops替換為使用wait()notify()notifyAll()spin locks(旋鎖),spin locks直觀而高效,polling loops則慢很多倍。

          ?

          PRAXIS56: 不要對上鎖對象(locked object)的object reference重新賦值

          當一個對象被鎖定,有可能其他線程會因同一個object lock而受阻(blocked),假如你對上鎖對象的object reference重新賦值,其他線程內懸而未決的那些locks將不再有意義。

          ?

          PRAXIS57: 不要調用stop()suspend()

          不要調用stop()suspend(),因為它們可能導致數據內部混亂,甚至引發死鎖。

          ?

          PRAXIS58: 通過線程之間的協作來中止線程

          你不應該調用stop(),如欲安全地停止線程,必須要求它們相互協作,才能姿態優雅的中止。

          ?



          Classes and Interfaces


          ?

          PRAXIS59: 運用interfaces支持多重繼承

          當你想要支持interface的單一繼承或多重繼承,或想要實現一個標識型的interface時,請使用interfaces。

          ?

          PRAXIS60: 避免interfaces中的函數發生沖突

          沒有任何辦法能夠阻止兩個interfaces使用同名的常數和函數,為了避免可能的沖突,應當小心命名常數和函數。

          ?

          PRAXIS61: 如需提供部分實現(partial implementation),請使用抽象類(abstract classes

          使用abstract class來為一個class提供部分實現,這些實現很可能對derived class是共通的。

          ?

          PRAXIS62: 區分interface、abstract classconcrete class

          一旦正確理解interface、abstract classconcrete class的差異,你就可以在設計是編碼時做出正確的選擇。

          ?

          PRAXIS63: 謹慎定義和實現不可變類(immutable classes

          如果你希望對象內容永遠不被改動,請使用不可變對象(immutable object),這種對象自動擁有“多線程安全性”。

          ?

          PRAXIS64: 欲傳遞或接收可變對象(mutable objects)的object references時,請使用clone()

          為了保證immutable objects,你必須在傳入和回傳它們時對它們施行clone()。

          ?

          PRAXIS65: 使用繼承或委托(delegation)來定義不可變類(immutable classes

          使用immutable interfacecommon interfacebase class,或是immutable delegation classes,來定義immutable classes

          ?

          PRAXIS66: 實現clone()時記得調用super.clone()

          當你實現一個clone(),總是應該調用super.clone()以確保產生正確的對象。

          ?

          PRAXIS67: 別只依靠finalize()清理non-memory(內存之外)的資源

          你不能保證finalize()是否被調用,以及何時被調用,因此,請專門實現一個public函數來釋放內存以外的資源。

          ?

          PRAXIS68: 在構造函數內調用non-final函數時要小心

          如果一個non-final函數被某個derived class覆蓋,在構造函數中調用這個函數可能會導致不可預期的結果。

          ?

          主站蜘蛛池模板: 宝应县| 利川市| 乌拉特后旗| 固镇县| 阿克陶县| 阜康市| 根河市| 咸宁市| 平谷区| 深州市| 衡水市| 宣化县| 叶城县| 特克斯县| 沙田区| 靖宇县| 繁峙县| 独山县| 郧西县| 建德市| 运城市| 丰都县| 武义县| 平乡县| 麻城市| 苗栗县| 长垣县| 左贡县| 敖汉旗| 万载县| 庄浪县| 虹口区| 安仁县| 年辖:市辖区| 资兴市| 汕头市| 丰原市| 萨嘎县| 马尔康县| 什邡市| 揭东县|