《Effective Java》

經(jīng)典重讀——亞馬遜鏈接


筆記鏈接


導(dǎo)圖:

Effective Java overview.png

筆記文本:

Effective Java
1 第2章 創(chuàng)建和銷毀對(duì)象
1.1 1. 考慮用靜態(tài)工廠方法代替構(gòu)造器
1.1.1 優(yōu)點(diǎn)
1.1.1.1 優(yōu)勢一:有名稱
1.1.1.2 優(yōu)勢二:不必在每次調(diào)用它們的時(shí)候都創(chuàng)建一個(gè)新對(duì)象
1.1.1.3 優(yōu)勢三:可以返回原返回類型的任何子類型的對(duì)象
1.1.1.4 優(yōu)勢四:在創(chuàng)建參數(shù)化類型實(shí)例時(shí),它們使代碼變得更簡潔
1.1.2 缺點(diǎn)
1.1.2.1 類如果不含有公有的或者受保護(hù)的構(gòu)造器,就不能被子類化
1.1.2.2 它們與其他靜態(tài)方法實(shí)際上沒有任何區(qū)別
1.2 2. 遇到多個(gè)構(gòu)造器參數(shù)時(shí)要考慮用構(gòu)建器
1.2.1 Builder
1.2.2 與構(gòu)造器相比的略微優(yōu)勢在于:builder可以有多個(gè)可變參數(shù)
1.2.3 雖然創(chuàng)建builder的開銷在實(shí)踐中可能不那么明顯,但是在某些十分注重性能的情況下,可能就成問題
1.2.4 builder比重疊構(gòu)造器更冗長,因此只在很多參數(shù)時(shí)才使用
1.3 3. 用私有構(gòu)造器或者枚舉類型強(qiáng)化Singleton屬性
1.3.1 單元素的枚舉類型已經(jīng)成為實(shí)現(xiàn)Singleton的最佳方法
1.4 4. 通過私有構(gòu)造器強(qiáng)化不可實(shí)例化的能力
1.4.1 弊端:使得其不能被子類化
1.5 5. 避免創(chuàng)建不必要的對(duì)象
1.5.1 對(duì)于同時(shí)提供了靜態(tài)工廠方法和構(gòu)造器的不可變類,通常可以使用靜態(tài)工廠方法而不是構(gòu)造器,以避免創(chuàng)建不必要的對(duì)象
1.5.2 除了重用不可變的對(duì)象之外,也可以重用那些已知不會(huì)被修改的可變對(duì)象
1.5.3 要優(yōu)先使用基本類型而不是裝箱基本類型,要當(dāng)心無意識(shí)的自動(dòng)裝箱
1.5.4 自己維護(hù)對(duì)象池只在對(duì)象非常重量級(jí)時(shí)才顯得必要,比如數(shù)據(jù)庫連接池,線程池
1.6 6. 消除過期的對(duì)象引用
1.6.1 一旦對(duì)象引用已經(jīng)過期,只需清空這些引用即可
1.6.2 緩存導(dǎo)致的內(nèi)存泄露
1.6.2.1 一種是確認(rèn)在緩存之外存在對(duì)某幾個(gè)項(xiàng)的鍵的引用,該項(xiàng)就有意義 ——可以用WeakHashMap代表緩存
1.6.2.2 針對(duì)“緩存項(xiàng)生命周期是否有意義”難以確認(rèn)的情況 ——緩存應(yīng)該時(shí)不時(shí)地清除掉沒用的項(xiàng)。這項(xiàng)清除工作可以由一個(gè)后臺(tái)線程來完成,或者也可以在給緩存添加新條目時(shí)順便清理(LinkedHashMap類利用它的removeEldestEntry方法可以很容易實(shí)現(xiàn))
1.6.2.3 第三種引發(fā)來源是:監(jiān)聽器和其他回調(diào)。 確保回調(diào)立即被當(dāng)做垃圾回收的最佳方法是只保存它們的弱引用 weak reference
1.7 7. 避免使用finalizer方法
1.7.1 通常是不可預(yù)測的
1.7.1.1 一個(gè)對(duì)象從不可用開始,到它的終結(jié)方法被執(zhí)行,這段時(shí)間是任意長的
1.7.2 使用它有一個(gè)非常嚴(yán)重的性能損失
1.7.3 顯示的終止方法通常與try-finally結(jié)合使用,以確保及時(shí)終止
1.7.4 用途:充當(dāng)安全網(wǎng)、本地對(duì)等體
1.7.5 結(jié)論:不應(yīng)該依賴終結(jié)方法來更新重要的持久狀態(tài)
1.7.6 結(jié)論:除非是作為安全網(wǎng),或者是為了終止非關(guān)鍵的本地資源,否則不要使用
2 第3章 對(duì)所有對(duì)象都通用的方法
2.1 8. 覆蓋equals時(shí)請(qǐng)遵守通用約定
2.1.1 建議:能不覆蓋就不要覆蓋
2.1.2 不用覆蓋的情形
2.1.2.1 類的每個(gè)實(shí)例本質(zhì)上都是唯一的
2.1.2.2 不關(guān)心類是否提供了“邏輯相等”
2.1.2.3 超類已經(jīng)覆蓋了equals,從超類繼承過來的行為對(duì)于子類也是合適的
2.1.2.4 類是私有的或是包級(jí)私有的,可以確定它的equals方法永遠(yuǎn)不會(huì)被調(diào)用
2.1.3 覆蓋的約定
2.1.3.1 自反性
2.1.3.2 對(duì)稱性
2.1.3.3 傳遞性
2.1.3.4 一致性
2.1.3.5 非空性
2.1.3.5.1 對(duì)于任何非null的引用值,x.equals(null)必須返回false
2.1.4 訣竅
2.1.4.1 使用== 檢查參數(shù)是否為這個(gè)對(duì)象的引用
2.1.4.2 使用instanceof檢查 參數(shù)是否為正確的類型
2.1.4.3 把參數(shù)轉(zhuǎn)換為正確的類型
2.1.4.4 對(duì)于該類中的每個(gè)關(guān)鍵域,檢查參數(shù)中的域是否與該對(duì)象中對(duì)應(yīng)的域相匹配
2.1.4.5 是否滿足:對(duì)稱、傳遞、一致
2.1.4.6 覆蓋equals時(shí)總要覆蓋hashCode
2.1.4.7 不要企圖讓equals方法過于智能
2.1.4.8 不要將equals聲明中的Object對(duì)象替換為其他類型
2.2 9. 覆蓋 equals時(shí)總要覆蓋 hashCode
2.2.1 最佳實(shí)踐:
2.2.1.1 @Override public int hashCode(){ int result = 17; result = 31 * result + areaCode; result = 31 * result + prefix; result = 31 * result + lineNumber; }
2.3 10. 總要覆蓋 toString
2.3.1 toString方法應(yīng)該返回對(duì)象中包含的所有值得關(guān)注的信息
2.4 11. 謹(jǐn)慎地覆蓋clone
2.4.1 通則:永遠(yuǎn)不要讓客戶去做任何類庫能夠替客戶完成的事情
2.4.2 最好提供某些其他途徑來代替對(duì)象拷貝,或者干脆不提供這樣的功能
2.4.3 另一個(gè)實(shí)現(xiàn)對(duì)象拷貝的好方法是提供一個(gè)拷貝構(gòu)造器或拷貝工廠
2.4.4 由于它有這么多缺點(diǎn),有些專家級(jí)的程序員干脆從來不去覆蓋clone方法,也從來不去調(diào)用它,除非拷貝數(shù)組
2.5 12. 考慮實(shí)現(xiàn)comparable接口
2.5.1 compareTo不但允許進(jìn)行簡單的等同性比較,而且允許執(zhí)行順序比較
2.5.2 如果你在編寫一個(gè)值類,它具有非常明顯的內(nèi)在排序關(guān)系,比如按字母順序、按數(shù)值順序或者按年代順序,那你就應(yīng)該堅(jiān)決考慮實(shí)現(xiàn)這個(gè)接口
2.5.3 如果一個(gè)類有多個(gè)關(guān)鍵域,那么你必須從最關(guān)鍵的域開始,逐步進(jìn)行到所有的重要域
3 第4章 類和接口
3.1 13. 使類和成員的可訪問性最小化
3.1.1 信息隱藏 或 封裝
3.1.2 盡可能地使每個(gè)類或者成員不被外界訪問
3.1.3 有一條規(guī)則限制了降低方法的可訪問性能力:如果方法覆蓋了超類中的一個(gè)方法,子類中的訪問級(jí)別就不允許低于超類中的訪問級(jí)別
3.1.4 注意:長度非零的數(shù)組總是可變的,所以,類具有公有的靜態(tài)final數(shù)組域或者返回這種域的訪問方法總是會(huì)出錯(cuò)
3.2 14. 在公有類中使用訪問方法而非公有域
3.2.1 如果類可以在它所在的包的外部進(jìn)行訪問,就提供訪問方法
3.2.2 如果類是包級(jí)私有的,或者是私有的嵌套類,直接暴露它的數(shù)據(jù)域并沒有本質(zhì)錯(cuò)誤
3.2.3 Java類庫的反面典型:Point和Dimension,暴露dimension類的內(nèi)部數(shù)據(jù)造成了嚴(yán)重的性能問題,而且這個(gè)問題依然存在
3.3 15. 使可變性最小化
3.3.1 理由:比可變類更加易于設(shè)計(jì)、實(shí)現(xiàn)和使用。它們不容易出錯(cuò),且更加安全
3.3.2 使類成為不可變需要遵循五條規(guī)則
3.3.2.1 1 不要提供任何會(huì)修改對(duì)象狀態(tài)的方法
3.3.2.2 2 保證類不會(huì)被擴(kuò)展
3.3.2.3 使所有的域都是final的
3.3.2.4 使所有的域都成為私有的
3.3.2.5 確保對(duì)于任何可變組件的互斥訪問
3.3.3 不可變對(duì)象的優(yōu)勢
3.3.3.1 不可變對(duì)象本質(zhì)上是線程安全的,它們不要求同步
3.3.3.2 不僅可以共享不可變對(duì)象,甚至可以共享它們的內(nèi)部信息
3.3.3.3 不可變對(duì)象為其他對(duì)象提供了大量的構(gòu)件
3.3.3.4 不可變對(duì)象真正唯一的缺點(diǎn)是,對(duì)于每個(gè)不同的值都需要一個(gè)單獨(dú)的對(duì)象
3.3.4 使類成為不可變的方法 (絕不允許自身被子類化)
3.3.4.1 1 使類成為final
3.3.4.2 2 讓類的所有構(gòu)造器都變成私有的或者包級(jí)私有的,并添加公有的靜態(tài)工廠來替代公有的構(gòu)造器
3.3.4.3 靜態(tài)工廠方法除了允許多個(gè)實(shí)現(xiàn)類的靈活性之外,這種方法還使得有可能通過改善靜態(tài)工廠的對(duì)象緩存能力,在后續(xù)的發(fā)行版中改進(jìn)該類的性能
3.3.4.4 還有許多其他優(yōu)勢,比如,提供一種其他功能的 構(gòu)造器 ,只需添加第二個(gè)靜態(tài)工廠,并且工廠的名字清楚地表明它的功能
3.3.5 如果你選擇讓自己的不可變類實(shí)現(xiàn)Serializable接口,并且包含一個(gè)或多個(gè)指向可變對(duì)象的域,就必須提供一個(gè)顯式的readObject或者readResolve方法
3.3.6 除非有很好的理由要讓類成為一個(gè)可變的類,否則就應(yīng)該是不可變的
3.3.7 如果類不能被做成不可變的,仍然應(yīng)該盡可能地限制它的可變性。降低對(duì)象可存在的狀態(tài)數(shù),可以更容易地分析該對(duì)象的行為,同時(shí)降低出錯(cuò)的可能性
3.4 16. 復(fù)合優(yōu)先于繼承
3.4.1 繼承是實(shí)現(xiàn)代碼重用的有力手段,但它并非永遠(yuǎn)是完成這項(xiàng)工作的最佳工具
3.4.2 與方法調(diào)用不同的是,繼承打破了封裝性
3.4.3 新類中的每個(gè)實(shí)例方法都可以調(diào)用被包含的現(xiàn)有類實(shí)例中對(duì)應(yīng)的方法,并返回它的結(jié)果,這被稱為“轉(zhuǎn)發(fā)”,新類中的方法被稱為轉(zhuǎn)發(fā)方法
3.4.4 使用復(fù)合的類也被稱為包裝類,這也正是“裝飾模式”
3.4.5 包裝類不適合用在回調(diào)框架中。 編寫轉(zhuǎn)發(fā)方法倒是有點(diǎn)瑣碎,但是只需要給每個(gè)接口編寫一次構(gòu)造器,轉(zhuǎn)發(fā)類則可以通過包含接口的包替你提供
3.4.6 只有當(dāng)子類真正是超類的子類型時(shí),才適合用繼承
3.4.7 如果在適合于使用復(fù)合的地方使用繼承,則會(huì)不必要地暴露實(shí)現(xiàn)細(xì)節(jié)。這樣得到的API會(huì)把你限制在原始的實(shí)現(xiàn)上,永遠(yuǎn)限定了類的性能
3.5 17. 要么為繼承而設(shè)計(jì),并提供文檔說明,要么就禁止繼承
3.5.1 說明可覆蓋方法的自用性
3.5.2 好的文檔應(yīng)該描述一個(gè)給定的方法做了什么,而不是如何做到的
3.5.3 對(duì)于為了繼承而設(shè)計(jì)的類,唯一的測試方法就是編寫子類
3.5.4 構(gòu)造器決不能調(diào)用可被覆蓋的方法
3.5.5 為了繼承而設(shè)計(jì)的類,對(duì)于這個(gè)類會(huì)有一些實(shí)質(zhì)性的限制
3.5.6 對(duì)于那些并非為了安全地進(jìn)行子類化而設(shè)計(jì)和編寫文檔的類,要禁止子類化
3.6 18. 接口優(yōu)于抽象類
3.6.1 現(xiàn)有的類可以很容易被更新,以實(shí)現(xiàn)新的接口
3.6.2 接口是定義mixin(混合類型)的理想選擇
3.6.3 接口允許我們構(gòu)造非層次結(jié)構(gòu)的類型框架
3.6.4 接口使得安全地增強(qiáng)類的功能成為可能
3.6.5 通過對(duì)你導(dǎo)出的每個(gè)重要接口都提供一個(gè)抽象的骨架實(shí)現(xiàn)類,把接口和抽象類的優(yōu)點(diǎn)結(jié)合起來
3.6.6 抽象類與接口相比有一個(gè)明顯優(yōu)勢:抽象類的演變比接口的演變要容易得多。如果在后續(xù)發(fā)行版中,你希望在抽象類中增加新的方法,始終可以增加具體方法,它包含合理的默認(rèn)實(shí)現(xiàn)。然后,該抽象類的所有實(shí)現(xiàn)都將提供這個(gè)新方法。對(duì)于接口,這樣做是行不通的
3.6.7 設(shè)計(jì)公有接口要非常謹(jǐn)慎。接口一旦被公開發(fā)行,并且已被廣泛實(shí)現(xiàn),再想改變這個(gè)接口幾乎是不可能的
3.7 19. 接口只用于定義類型
3.7.1 有一種接口被稱為 常量接口。這種接口不包含任何方法,它只包含靜態(tài)final域,每個(gè)域都導(dǎo)出一個(gè)常量。使用這些常量的類實(shí)現(xiàn)這個(gè)接口,以避免用類名來修飾常量名。
3.7.2 應(yīng)該將這種量導(dǎo)出
3.8 20. 類層次優(yōu)于標(biāo)簽類
3.8.1 缺點(diǎn)
3.8.1.1 充斥著樣板代碼,包括枚舉聲明、標(biāo)簽域以及條件語句
3.8.1.2 標(biāo)簽類過于冗長、容易出錯(cuò),并且效率低下
3.9 21. 用函數(shù)對(duì)象表示策略
3.9.1 比較器函數(shù)代表一種為元素排序的策略
3.9.2 我們?cè)谠O(shè)計(jì)具體的策略類時(shí),還需要定義一個(gè)策略接口
3.10 22. 優(yōu)先考慮靜態(tài)成員類
3.10.1 嵌套類是指被定義在另一個(gè)類的內(nèi)部的類。嵌套類有四種
3.10.1.1 靜態(tài)成員類
3.10.1.2 非靜態(tài)成員類
3.10.1.3 匿名類
3.10.1.4 局部類
3.10.2 如果聲明成員類不要求訪問外圍實(shí)例,就要始終把static修飾符放在它的聲明中
4 第5章 泛型
4.1 23. 請(qǐng)不要在新代碼中使用原生態(tài)類型
4.2 24. 消除非受檢警告
4.2.1 要盡可能消除每一個(gè)非受檢警告
4.2.2 如果無法消除警告,同時(shí)可以證明引起警告的代碼是類型安全的,(只有在這種情況下才)可以用一個(gè)@SuppressWarning("uncheck")注解來禁止這條警告
4.3 25. 列表優(yōu)先于數(shù)組
4.3.1 數(shù)組與泛型相比,有兩個(gè)重要不同點(diǎn)

    4.3.1.1 1 數(shù)組是協(xié)變的
    4.3.1.2 2 數(shù)組是具體化的

4.4 26. 優(yōu)先考慮泛型
4.4.1 編寫自己的泛型會(huì)比較困難,但是值得花些時(shí)間去學(xué)習(xí)如何編寫
4.5 27. 優(yōu)先考慮泛型方法
4.5.1 泛型方法就像泛型一樣,使用起來比要求客戶端轉(zhuǎn)換輸入?yún)?shù)并返回值的方法來得更加安全,也更加容易。
4.5.2 就像泛型一樣,你應(yīng)該確保新方法可以不用轉(zhuǎn)換就能使用,這通常意味著要將它們泛型化
4.6 28. 利用有限制通配符來提升API的靈活性
4.6.1 <? Extends E>
4.6.2 <? super E>
4.6.3 PECS 表示: producer-extends, consumer-super
4.6.4 所有的comparable和comparator都是消費(fèi)者
4.7 29. 優(yōu)先考慮類型安全的異構(gòu)容器
5 第6章 枚舉和注解
5.1 第30條 用enum代替int常量
5.1.1 因?yàn)闆]有可訪問的構(gòu)造器,枚舉類型是真正的final
5.1.2 枚舉是實(shí)例受控的
5.1.3 它們是單例的泛型化,本質(zhì)上是單元素的枚舉
5.1.4 你可以增加或重新排列枚舉類型中的常量,而無需重新編譯它的客戶端代碼,因?yàn)閷?dǎo)出常量的域在枚舉類型和它的客戶端之間提供了一個(gè)隔離層:常量值并沒有被編譯到客戶端代碼中,而是在int枚舉模式之中
5.1.5 最終,可以通過調(diào)用toString方法將枚舉轉(zhuǎn)化成可打印的字符串
5.1.6 除了完善了int枚舉模式不足之外,枚舉類型還允許添加任意的方法和域,并實(shí)現(xiàn)任意接口
5.1.7 將不同的行為與每個(gè)枚舉常量關(guān)聯(lián)起來:在枚舉類型中聲明一個(gè)抽象的方法
5.1.7.1 pubic enum Operation{ PLUS{double apply(double x, double y){return x + y;}}, MINUS{double apply(double x, double y){return x - y;}}, TIMES{double apply(double x, double y){return x * y;}}, DIVIDE{double apply(double x, double y){return x / y;}}; abstract double apply(double x, double y); }
5.1.7.2 如果給第二版添加新常量,你就不可能會(huì)忘記提供apply方法
5.1.8 特定于常量的方法實(shí)現(xiàn)可以與特定于常量的數(shù)據(jù)結(jié)合起來
5.1.8.1 pubic enum Operation{ PLUS("+") {double apply(double x, double y){return x + y;}}, MINUS("-") {double apply(double x, double y){return x - y;}}, TIMES("*") {double apply(double x, double y){return x * y;}}, DIVIDE("/") {double apply(double x, double y){return x / y;}}; private final String symbol; Operation(String symbol) {this.symbol = symbol;} @Override public String toString(){ return this.sybol;} abstract double apply(double x, double y); }
5.1.9 枚舉類型有一個(gè)自動(dòng)產(chǎn)生的valueOf(String )方法,它將常量的名字轉(zhuǎn)變成常量本身
5.1.10 策略枚舉
5.1.10.1 嵌套策略枚舉之后,枚舉中就不需要switch語句或者特定于常量的方法實(shí)現(xiàn)了。雖然這種模式?jīng)]有switch語句那么簡潔,但更加安全,也更加靈活
5.2 第31條 用實(shí)例域代替序數(shù)
5.2.1 永遠(yuǎn)不要根據(jù)枚舉的序數(shù)導(dǎo)出與它關(guān)聯(lián)的值,而是要將它保存在一個(gè)實(shí)例域中
5.2.2 ordinal()——大多數(shù)程序員都不需要這個(gè)方法,它是設(shè)計(jì)成用于像EnumSet和EnumMap這種基于枚舉的通用數(shù)據(jù)結(jié)構(gòu)的
5.3 第32條 用EnumSet代替位域
5.3.1 枚舉類型要用于集合中,沒有理由用位域來表示它們
5.4 第33條 用EnumMap代替序數(shù)索引
5.4.1 使用EnumMap,運(yùn)行速度可以與使用序數(shù)的程序相媲美,沒有不安全的轉(zhuǎn)換,不必手工標(biāo)注這些索引的輸出;計(jì)算數(shù)組索引時(shí)也不可能出錯(cuò)
5.4.2 之所以能與通過序數(shù)索引的數(shù)組相媲美,是因?yàn)镋numMap在內(nèi)部使用了這種數(shù)組
5.4.3 最好不要用序數(shù)來索引數(shù)組,而要使用EnumMap
5.5 第34條 用接口模擬可伸縮的枚舉
5.5.1 雖然無法編寫可擴(kuò)展的枚舉類型,卻可以通過編寫接口以及實(shí)現(xiàn)該接口的基礎(chǔ)枚舉類型,對(duì)它進(jìn)行模擬
5.6 第35條 注解優(yōu)先于命名模式
5.6.1 示例
5.6.1.1 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Test{ }
5.6.1.2 這種注解稱為元注解
5.7 第36條 堅(jiān)持使用Override注解
5.7.1 能夠避免疏漏的 重載
5.8 第37條 用標(biāo)記接口定義類型
5.8.1 定義:沒有包含方法聲明的接口,而只是指明一個(gè)類實(shí)現(xiàn)了具有某種屬性的接口
6 第7章 方法
6.1 第38條 檢查參數(shù)的有效性
6.2 第39條 必要時(shí)進(jìn)行保護(hù)性拷貝
6.2.1 假設(shè)類的客戶端會(huì)盡其所能來破壞這個(gè)類的約束條件,因此你必須保護(hù)性地設(shè)計(jì)程序
6.2.2 為了保護(hù)類的內(nèi)部信息免受直接訪問修改的攻擊,對(duì)于構(gòu)造器的每個(gè)可變參數(shù)進(jìn)行保護(hù)性拷貝是必要的
6.2.3 對(duì)與參數(shù)類型可以被不可信任方子類化的參數(shù),請(qǐng)不要使用clone方法進(jìn)行保護(hù)性拷貝
6.2.4 雖然替換構(gòu)造器就可以成功地避免上述攻擊,但是改變Period實(shí)例仍然是有可能的,因?yàn)樗脑L問方法提供了對(duì)其可變內(nèi)部成員的訪問能力 為了防御這種攻擊,只需要修改訪問方法,使它返回可變內(nèi)部域的保護(hù)性拷貝即可
6.3 第40條 謹(jǐn)慎設(shè)計(jì)方法簽名
6.3.1 謹(jǐn)慎選擇方法的名稱
6.3.2 不要過于追求提供便利的方法
6.3.2.1 每個(gè)方法都應(yīng)該盡其所能。
6.3.2.2 方法太多會(huì)使類難以學(xué)習(xí)、使用、文檔化、測試和維護(hù)
6.3.2.3 只有當(dāng)一項(xiàng)操作被經(jīng)常使用時(shí),才考慮為它提供快捷方法,如果不能確定,還是不提供為好
6.3.3 避免過長的參數(shù)列表
6.3.3.1 相同類型的長參數(shù)列表格外有害
6.3.3.2 例如,List接口提供了subList方法,返回子列表的視圖(view)
6.3.3.3 解決方法
6.3.3.3.1 1 分解為多個(gè)方法
6.3.3.3.2 2 創(chuàng)建輔助類
6.3.3.3.3 3 采用builder模式
6.3.3.4 對(duì)參數(shù)類型,要優(yōu)先使用接口而不是類
6.3.3.5 對(duì)于boolean參數(shù),要優(yōu)先使用兩個(gè)元素的枚舉類型
6.4 第41條 慎用重載
6.4.1 對(duì)于重載方法的選擇是靜態(tài)的,而對(duì)于被覆蓋的方法的選擇則是動(dòng)態(tài)的
6.4.2 安全而保守的策略是,永遠(yuǎn)不要導(dǎo)出兩個(gè)具有相同參數(shù)數(shù)目的重載方法
6.5 第42條 慎用可變參數(shù)
6.5.1 EnumSet類對(duì)它的靜態(tài)工廠使用這種方法,最大限度地減少創(chuàng)建枚舉集合的成本。枚舉集合為位域提供在性能方面有競爭力的替代方法
6.6 第43條 返回零長度的數(shù)組或者集合,而不是null
6.6.1 對(duì)于不返回任何元素的調(diào)用,每次都返回同一個(gè)零長度數(shù)組是有可能的,因?yàn)榱汩L度數(shù)組是不可變的
6.7 第44條 為所有導(dǎo)出的API元素編寫文檔注釋
6.7.1 為了正確地編寫API文檔,必須在每個(gè)被導(dǎo)出的 類、接口、構(gòu)造器、方法和域聲明之前增加一個(gè)文檔注釋
6.7.2 方法的文檔注釋應(yīng)該簡潔地描述出它和客戶端之間的約定
6.7.2.1 precondition
6.7.2.2 postcondition
6.7.2.3 side effect
6.7.2.4 thread safety
6.7.3 可以使用HTML標(biāo)簽
6.7.4 使用{@code}標(biāo)簽
6.7.5 {@literal}
7 第8章 通用程序設(shè)計(jì)
7.1 第45條 將局部變量的作用域最小化
7.1.1 幾乎每個(gè)局部變量的聲明都應(yīng)該包含一個(gè)初始化表達(dá)式
7.1.2 使用for循環(huán),可以大大降低 “剪切-粘貼”錯(cuò)誤
7.1.3 使用for循環(huán)與使用while相比還有另外一個(gè)優(yōu)勢:更簡短,從而增強(qiáng)可讀性
7.2 第46條 for-each循環(huán)優(yōu)先于傳統(tǒng)的for循環(huán)
7.2.1 for-each循環(huán)不僅讓你遍歷集合和數(shù)組,還讓你遍歷任何實(shí)現(xiàn)Iterable接口的對(duì)象
7.2.2 如果你在編寫的類型表示的是一組元素,即使你選擇不讓它實(shí)現(xiàn)Collection,也要讓它實(shí)現(xiàn)Iterable。這樣可以允許用戶利用for-each循環(huán)遍歷你的類型
7.2.3 有三種常見情況無法使用for-each循環(huán)
7.2.3.1 過濾
7.2.3.2 轉(zhuǎn)換
7.2.3.3 平行迭代
7.3 第47條 了解和使用類庫
7.4 第48條 如果需要精確答案,請(qǐng)避免使用float和double
7.4.1 二進(jìn)制浮點(diǎn)運(yùn)算
7.4.2 float和double不適合貨幣計(jì)算
7.4.3 使用BigDecimal、int或者long進(jìn)行
7.5 第49條 基本類型優(yōu)先于裝箱基本類型
7.5.1 裝箱類型的合理用處
7.5.1.1 作為集合中的元素、鍵和值
7.5.1.2 在參數(shù)化類型中,必須使用裝箱基本類型作為類型參數(shù)
7.5.1.3 在反射調(diào)用時(shí),必須使用裝箱基本類型
7.6 第50條 如果其他類型更合適,則盡量避免使用字符串
7.6.1 字符串不適合代替其他的值類型
7.6.2 字符串不適合代替枚舉類型
7.6.3 字符串不適合代替聚集類型
7.6.4 字符串不適合代替能力表
7.7 第51條 當(dāng)心字符串連接的性能
7.7.1 使用StringBuilder替代
7.8 第52條 通過接口引用對(duì)象
7.8.1 如果你養(yǎng)成了用接口作為類型的習(xí)慣,你的程序?qū)⒏屿`活
7.8.2 如果沒有合適的接口存在,完全可以用類而不是接口來引用對(duì)象
7.9 第53條 接口優(yōu)先于反射機(jī)制
7.9.1 反射
7.9.1.1 喪失了編譯時(shí)類型檢查的好處
7.9.1.2 執(zhí)行反射訪問所需要的代碼非常笨拙和冗長
7.9.1.3 性能損失
7.10 第54條 謹(jǐn)慎地使用本地方法
7.10.1 使用本地方法提升性能的做法不值得提倡
7.11 第55條 謹(jǐn)慎地進(jìn)行優(yōu)化
7.11.1 優(yōu)化的弊大于利
7.11.2 要努力編寫好的程序而不是快的程序
7.11.3 努力避免那些限制性能的設(shè)計(jì)決策
7.11.4 要考慮API設(shè)計(jì)決策的性能后果
7.11.5 為了獲得好的性能而對(duì)API進(jìn)行包裝,這是一種非常不好的想法
7.12 第56條 遵守普遍接受的命名規(guī)則
8 第9章 異常
8.1 第57條 只針對(duì)異常的情況才使用異常
8.1.1 基于異常的模式比標(biāo)準(zhǔn)模式要慢得多
8.2 第58條 對(duì)可恢復(fù)的情況使用受檢異常,對(duì)編程錯(cuò)誤使用運(yùn)行時(shí)異常
8.2.1 受檢異常
8.2.2 用運(yùn)行時(shí)異常來表明編程錯(cuò)誤
8.3 第59條 避免不必要地使用受檢異常
8.4 第60條 優(yōu)先使用標(biāo)準(zhǔn)異常
8.5 第61條 拋出與抽象相對(duì)應(yīng)的異常
8.5.1 更高層的實(shí)現(xiàn)應(yīng)該捕獲低層的異常,同時(shí)拋出可以按照高層抽象進(jìn)行解釋的異常
8.5.2 異常鏈
8.6 第62條 每個(gè)方法拋出的異常都要有文檔
8.6.1 單獨(dú)聲明受檢異常,使用Javadoc的@throws標(biāo)記
8.6.2 不要在非受檢異常上使用@throws
8.7 第63條 在細(xì)節(jié)消息中包含能捕獲失敗的信息
8.7.1 為了捕獲失敗,異常的細(xì)節(jié)信息應(yīng)該包含所有“對(duì)該異常有貢獻(xiàn)”的參數(shù)和域的值
8.8 第64條 努力使失敗保持原子性
8.8.1 失敗的方法調(diào)用應(yīng)該使對(duì)象保持在被調(diào)用之前的狀態(tài)
8.9 第65條 不要忽略異常
8.9.1 空的catch塊達(dá)不到應(yīng)有的目的
8.9.2 至少包含一條忽略的說明
9 第10章 并發(fā)
9.1 第66條 同步訪問共享的可變數(shù)據(jù)
9.1.1 Java語言規(guī)范保證讀或者寫一個(gè)變量是原子性的
9.1.2 volatile修飾符不執(zhí)行互斥訪問,但它可以保證任一線程在讀取該域時(shí)都將看到最近剛被寫入的值
9.1.3 使用volatile時(shí),務(wù)必要小心,++操作并不是原子性的
9.1.4 AtomicInt、AtomicLong
9.1.4.1 getAndIncrement
9.1.5 多線程共享可變數(shù)據(jù)時(shí),每個(gè)讀或者寫數(shù)據(jù)的線程都必行執(zhí)行同步
9.2 第67條 避免過度同步
9.3 第68條 executor和task優(yōu)先于線程
9.3.1 Executor FrameWork中有一個(gè)可以替代Timer的東西,即ScheduleThreadPoolExecutor 雖然就Timer更加容易,但executor更靈活。Timer對(duì)于長期運(yùn)行任務(wù)時(shí)會(huì)影響到定時(shí)準(zhǔn)確性。 如果Timer唯一的線程拋出未被捕獲異常,Timer就會(huì)停止執(zhí)行,而executor支持多個(gè)線程,并且優(yōu)雅地從拋出的未受檢異常的任務(wù)中恢復(fù)
9.4 第69條 并發(fā)工具優(yōu)先于wait和notify
9.4.1 既然正確地使用wait和notify比較困難,就應(yīng)該用更高級(jí)的并發(fā)工具來代替
9.4.2 concurrent工具分三類:Executor Framework、并發(fā)集合 以及 同步器
9.4.2.1 并發(fā)集合為標(biāo)準(zhǔn)的集合接口(如List、Queue和Map)
9.4.2.1.1 ConcurrentHashMap出了提供卓越的并發(fā)性之外,速度也非常快
9.4.2.1.2 優(yōu)先使用ConcurrentHashMap而不是Hashtable或者Collections.synchronizedMap
9.4.2.2 有些集合接口已經(jīng)通過阻塞操作進(jìn)行了擴(kuò)展,他們會(huì)一直等待可以成功執(zhí)行為止
9.4.2.2.1 如BlockingQueue
9.4.2.2.2 不出所料,大多數(shù)ExecutorService實(shí)現(xiàn)(包括ThreadPoolExecutor)都使用BlockingQueue
9.4.2.3 同步器 是一些使線程能夠等待另一個(gè)線程的對(duì)象,允許它們協(xié)調(diào)動(dòng)作
9.4.2.3.1 最常用的是CountDownLatch和Semaphore
9.4.2.3.2 對(duì)于間歇式定時(shí),應(yīng)該使用System.nanoTime,更加精準(zhǔn)
9.4.2.3.3 傳遞給Timer方法的executor必須允許創(chuàng)建至少與指定并發(fā)級(jí)別一樣多的線程,否則這個(gè)測試就永遠(yuǎn)不會(huì)結(jié)束,這就是線程饑餓死鎖
9.4.3 使用wait和notify就像用“并發(fā)匯編語言”進(jìn)行編程一樣
9.4.4 維護(hù)時(shí):一般情況下你應(yīng)該優(yōu)先使用notifyAll,而不是notify
9.5 第70條 線程安全性的文檔化
9.6 第71條 慎用延遲初始化
9.6.1 除非絕對(duì)必要,否則就不要這么做
9.6.2 在大多數(shù)情況下,正常的初始化要優(yōu)先于延遲初始化
9.6.3 如果處于性能考慮需要對(duì)實(shí)例域使用延遲初始化,就使用雙重檢查模式
9.7 第72條 不要依賴于線程調(diào)度器
9.7.1 任何依賴于線程調(diào)度器來達(dá)到正確性或者性能要求的程序,很有可能都是不可移植的
9.7.2 不要依賴Thread.yield或者線程優(yōu)先級(jí)。這些設(shè)施僅僅對(duì)調(diào)度器作些按時(shí)
9.7.3 線程優(yōu)先級(jí)可以用來提高一個(gè)已經(jīng)能夠正常工作的程序的服務(wù)質(zhì)量,但永遠(yuǎn)不應(yīng)該用來“修正”一個(gè)原本不能正常工作的程序
9.8 第73條 避免使用線程組
10 第11章 序列化
10.1 第74條 謹(jǐn)慎實(shí)現(xiàn)Serializable接口
10.1.1 代價(jià)
10.1.1.1 降低了改變這個(gè)類的實(shí)現(xiàn)的靈活性
10.1.1.2 增加了出現(xiàn)Bug和安全漏洞的可能性
10.1.1.3 相關(guān)的測試負(fù)擔(dān)增加
10.2 第75條 考慮使用自定義的序列化形式
10.3 第76條 保護(hù)性地編寫readObject方法
10.4 第77條 對(duì)于實(shí)例控制,枚舉類型優(yōu)先于readResolve
10.5 第78條 考慮用序列化代理代替序列化實(shí)例

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,772評(píng)論 3 422
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評(píng)論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評(píng)論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,960評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,350評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,549評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,104評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,914評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,089評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,340評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評(píng)論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,834評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,106評(píng)論 2 375

推薦閱讀更多精彩內(nèi)容