1. 程式人生 > >Effective java第二版讀書筆記

Effective java第二版讀書筆記

下面對Effective java第二版中的技術點進行總結,未讀待續,先儲存著。

序號 技巧 優點 缺點及注意事項
1 用靜態工廠方法代替構造器 有名稱, 不必在每次呼叫時都建立一個新物件,可返回原返回型別的任何子型別物件,建立引數化例項時,程式碼更簡潔 若類不含有公有或受保護的構造器,不能被子類化,它們與其他靜態方法實際上沒有任何區別
2 多個構造器引數時考慮用構造器 Builder模式,利用所有必要的引數呼叫構造器,得到一個builder物件,再在builder物件上呼叫類似於setter方法 如果類的構造器或靜態工廠中有多個引數
3 用私有構造器或列舉型別強化Singleton屬性 1.私有構造器: public class Elvis {
public static final Elvis INSTANCE = new Elvis();
private Elvis() {…}
}
2. 列舉:public enum Elvis {
INSTANCE;
}
Singleton指僅被例項化一次的類
4 通過私有構造器強化不可例項化的能力 public class UtilityClass {
private UtilityClass() {…}
}
只包含靜態方法和靜態域的類
5 避免建立不必要的物件 優先使用基本型別int, long, boolean等而不是裝箱基本型別Integer,Long, Boolean; 維持物件池; 物件能重用時儘量用同一物件,考慮用介面卡;
6 消除過期的物件引用 將過期物件設為null,使用弱引用WeakHashmap
7 避免使用終結方法 作為安全網或是為了終止非關鍵的本地資源時使用,仍要呼叫super.finalize 不能保證會被及時執行;有效能損失;
8 覆蓋equals時遵守的通用約定 自反性、對稱性、傳遞性、一致性、非空性 使用==檢查“引數是否為這個物件的引用”、使用instanceof操作符檢查“引數是否為正確型別”
9 覆蓋equals時總要覆蓋hashCode 相等的物件必須有相等的雜湊碼
10 始終要覆蓋toString 使類返回物件中包含值得關注的資訊 正常Object的toString返回的字串是“類名[email protected]+無符號十六進位制雜湊碼”,不是使用者期望的
11 謹慎地覆蓋clone 實現了cloneable介面的類,必須要實現clone方法 克隆必須保證不會傷害到原始物件,確保正確地建立被克隆物件中的約束條件
12 考慮實現Comparable介面 compareTo允許順序比較 若兩個被比較的compareTo物件引用不同類的物件,會拋異常
13 使類和成員的可訪問性最小化 儘可能使每個類或成員不被外界訪問,資訊隱藏 例項域不能是公有的,包含公有可變域的類不是執行緒安全的
14 在公有類中使用訪問方法而非公有域 對於可變類,應該用私有域和公有訪問(getter)/設值(setter)方法代替 若公有類暴露了它的資料域,將來想改變其內部表示法比較困難
15 使可變性最小化 不可變類即其例項不能被修改的類,主要有:不要提供任何會修改物件狀態的方法;保證類不會被擴充套件;使所有的域都是final的;所有域都成為私有 在特定情況下存在潛在的性以問題
16 複合優先於繼承 包裝類比子類更健壯,功能更強大;不會暴露太多實現細節 封裝違背了封裝原則
17 要麼為繼承而設計,並提供文件說明,要麼就禁止繼承 類文件必須精確地描述覆蓋每具方法所帶來的影響;構造器不能呼叫可被覆蓋的方法 對於並非為了進行子類化而設計和編寫文件的類,要禁止子類化,可以把類宣告為final型,或是把所有的構造器都變成私有的
18 介面優於抽象類 介面是定義mixin(混合型別)的理想民選擇;允許構造非層次結構的型別框架 介面一旦公開且被廣泛實現,再想改變幾乎不可能;(兩者區別:抽象類允許包含某些方法實現,介面不允許;類只能單繼承,實現抽象類只能成為一個子類,而介面不受此限制)
19 介面只用定義型別 類實現介面時,介面就充當可以引用這個類的例項型別 介面應該只被用來定義型別,不應該被用來匯出常量
20 類層次優先於標籤類 類層次可以用來反映型別之間本質上的層次關係,有助於增強靈活性 若使用標籤類,域不能做成final型,且初始化出錯,很容易導致執行時失敗
21 用函式物件表示策略 函式指標是用來實現策略模式,為實現這種模式,需要宣告一個介面來表示策略,為每個具體策略宣告一個實現該介面的類
22 優先考慮靜態成員類 如果宣告成員類不要求訪問外圍例項,就要始終把static修飾符放在它的宣告中 非靜態成員類的每個例項都隱含著與外圍類的一個外圍例項相關聯,保持這份引用需要消耗時間和空間
23 請不要在新程式碼中使用原生態型別 使用原生態型別,就失掉了泛型在安全性和表述性方面所有優勢 List泛型;List無限制萬用字元型別,表示只能包含某種未知物件型別的一個集合;List原生態型別,脫離了泛型系統,不安全
24 消除非受檢的警告 每一條警告都表示可能在執行時丟擲ClassCastException異常 如果無法消除警告,且可證明引起警告的程式碼是型別安全的(可以使用@SuppressWarnings(“unchecked”))
25 列表優先於陣列 陣列在執行時才檢查元素型別約束,沒有編譯時的型別安全;泛型是通過擦除來實現,只在編譯時強化型別資訊,在執行時丟棄它們的元素型別資訊 擦除就是使泛型可以與沒有使用泛型的程式碼隨意進行互用,陣列和泛型不能很好的混合使用
26 優先考慮泛型 使用泛型比在客戶端進行型別轉換更安全,也更容易 把現有型別都泛型化
27 優先考慮泛型方法 使用泛型比在客戶端輸入引數和返回值的方法更安全,也更容易 像型別一樣,可以確保方法可以不用轉換就能使用
28 利用有限制萬用字元來提升API的靈活性 為獲取最大限度的靈活性,要在表示生產者或消費者的輸入引數上使用萬用字元型別 如Comparable優先於Comparable
29 優先考慮型別安全的異構容器 將鍵進行引數化而不是將容器引數化,將引數化的鍵提交給容器 不可用在不可具體化的型別中,如List沒有對應的Class物件;客戶端很容易被破化型別安全,如使用原生態形式
30 用enum代替int常量 列舉所有的域都應該是final的,易讀,更安全,功能也更強大 列舉在裝載或初化時會有空間和時間的成本
31 用例項域代替序數 可以將列舉的序儲存在一個例項域中,如public enum Ensemble {SOLO(1), DUEP(2), …} ordinal是為EnumSet和EnumMap型別的資料結構用的,為表示序號,不要用ordinal方法
32 用EnumSet代替位域 EnumSet可從單個列舉型別中撮多個值的多個集合,批處理,如removeAll和retainAll,都是用位演算法實現的 Java 1.6以前,無法建立不可變的EnumSet
33 用EnumMap代替序數索引 如果要表示是關係是多維度的,就命名用EnumMap<…, EnumMap<…>> EnumMap內部使用了陣列,集Map豐富功能和型別安全與陣列的快速於一體
34 用介面模擬可伸縮的列舉 定義一個介面,讓列舉實現這個介面
35 註解優先於命名模式 拼寫錯誤,編譯期間就會發現;註解中陣列引數是優化的單元素陣列 命名模式的幾個缺陷:使用者單詞拼寫錯誤,不會報錯也不會執行,造成錯誤的安全感;無法確保它們只用於相應的程式元素上;沒有提供引數值與程式元素關聯的方法;
36 堅持使用Override註解 如果想要覆蓋超類中宣告的方法,則使用Override註解 編譯器可以防止犯錯
37 用標記介面定義型別 可通過預設的方式新增一個或多個註解型別元素,給已被使用註解型別新增更多資訊 標記介面是指沒有包含方法宣告的介面,只是指明一個類實現了具有某種屬性的介面,如Serializable介面
38 檢查引數的有效性 非公有方法可以使用斷言來檢查它們的引數 設計引數限制檢查時,視具體需求而定,如果檢查很費時間或是導致操作非原子性,會加大程式執行時間
39 必要時進行保護性拷貝 保護性拷貝是在檢查引數有效性之前進行,有效性檢查的是拷貝之後的物件