EffectiveJAVA.html
Effective JAVA
第2章 創建銷毀對象
1.考慮用靜態工廠方法代替構造器
優點
·靜態工廠方法有名稱
·不用每次都創建新實例
·可以返回遠返回類型的任何子類型的對象
·在創建參數化類型實例的時候代碼更簡潔
缺點
·不能被子類化
·它們與其他的靜態方法實際上沒有任何區別
2.遇到多個構造器參數時要考慮用構造器
如果類的構造器或者靜態工廠中具有多個參數,可以考慮使用Builder模式
3.用私有構造器或者枚舉類型強化Singleton屬性
編寫一個包含單個元素的枚舉類型
public enum Elvis{
INSTANCE;
public void leaveTheBuilding*(){
...}
}
">
public enum Elvis{
INSTANCE;
public void leaveTheBuilding*(){
...}
}
4.通過私有構造器強化不可實例化的能力
讓不需要實例化的類擁有私有(private)構造器來避免被實例化
//Noninstantiable utility class
public enum UtilityClass{
private UtilityClass(){
throw new AssertinError();
}
...
}
">
public enum UtilityClass{
private UtilityClass(){
throw new AssertinError();
}
...
}
5.避免創建不必要的對象
使用靜態的初始化器(initialize)避免創建重復的Calendar,TimeZone和Date實例
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class Person {
private Date birthDate;
private static final Date BOOM_START;
private static final Date BOOM_END;
static {
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_START = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_END = gmtCal.getTime();
}
public boolean isBabyBoomer() {
return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) <= 0;
}
}
">
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
public class Person {
private Date birthDate;
private static final Date BOOM_START;
private static final Date BOOM_END;
static {
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone(
"GMT"));
gmtCal.set(
1946, Calendar.JANUARY,
1,
0,
0,
0);
BOOM_START = gmtCal.getTime();
gmtCal.set(
1965, Calendar.JANUARY,
1,
0,
0,
0);
BOOM_END = gmtCal.getTime();
}
public boolean isBabyBoomer() {
return birthDate.compareTo(BOOM_START) >=
0 && birthDate.compareTo(BOOM_END) <=
0;
}
}
優先使用基本類型而不是裝箱基本類型,要當心無意識的自動裝箱。
6.消除過期的對象引用
一旦對象引用已經過期,只需清空這些引用即可。
7.避免使用終結方法
終結方法(finalizer)通常是不可預測的,也是很危險的,一般情況下是不必要的。
不應該依賴終結方法來更新重要的持久狀態。
顯式終止方法的典型例子:InputStream,OutputStream,java.sql.Connection的Close
第3章 對于所有對象都通用的方法
8.覆蓋equals時請遵守通用約定
·類的每個實例本質上都是唯一的
·不關心類是否提供了“邏輯相等”
·超類已經覆蓋了equals,從超類繼承過來的行為對于子類也是合適的
·類是私有的或是包級私有的,應該覆蓋父類的equals方法保證永遠不會被調用
9.覆蓋equals時總要覆蓋hashCode
10.始終要覆蓋toString
11.謹慎地覆蓋clone
12.考慮實現Comparable接口
第4章 類和接口
13.使類和成員的可訪問性最小化
14.在公有類中使用訪問方法而非公有域
15.使可變性最小化
1.不要提供任何會修改對象狀態的方法
2.保證類不會被擴展
3.使所有域都是final
4.使所有域都成為私有的
5.確保對于任何可變組建的互斥訪問
16.復合優先于繼承
17.要么為繼承而設計,并提供文檔說明,要么就禁止繼承
18.接口優于抽象類
- 現有的類可以很容易被更新,以實現新的接口
- 接口是定義minin(混合類型)的理想選擇
- 接口允許我們構造非層次結構的類型框架
19.接口只用于定義類型
20.類層次優于標簽類
21.用函數對象表示策略
22.優先考慮靜態成員類
第5章 泛型
23.請不要在新代碼中使用原生態類型
24.消除非受檢警告
SuppressWarnings注解始終在盡可能小的范圍中使用。
25.列表預先于數組
數組是協變得(covariant)。
數組是具體化的。
26.優先考慮泛型
27.優先考慮泛型方法
28.利用有限制通配符來提升API的靈活性
29.優先考慮類型安全的已購容器
第6章 枚舉和注解
30.用enum代替int常量
31.用實例域代替序數
32.用EnumSet代替位域
33.用EnumMap代替序數索引
34.用接口模擬可伸縮的枚舉
35.注解優先于命名模式
36.堅持使用Override注解
37.用標記接口定義類型
第7章 方法
38.檢查參數的有效性
39.必要時進行保護性拷貝
40.謹慎設計方法簽名
謹慎地選擇方法的名稱
不要過于追求提供便利的方法
避免過長的參數列表
41.慎用重載
42.慎用可變參數
43.返回零長度的數組或集合,而不是null
44.為所有到處的API元素編寫文檔注釋
第8章 通用程序設計
45.將局部變量的作用域最小化
46.for-each循環優先于傳統的for循環
無法使用for-each的情形
1.過濾
2.轉換
3.平行迭代
47.了解和使用類庫
48.如果需要精確的答案,請避免使用float和double
正確的做法:使用BigDecimal,int或者long進行貨幣計算
49.基本類型優先于裝箱基本類型
50.如果其他類型更適合,則盡量避免使用字符串
字符串不適合替代其他的值類型
字符串不適合代替枚舉類型
字符串不適合替代聚集類型
字符串也不適合太呆能力表(capabilities)
51.當心字符串連接的性能
52.通過接口引用對象
53.接口優先于反射機制
反射機制的代價
喪失了編譯時類型檢查的好處
執行反射訪問所需要的代碼非常笨拙和冗長
性能損失
54.謹慎地使用本地方法
55.謹慎地進行優化
56.遵守普遍接受的命名慣例
第9章 異常
57.只針對異常的情況才使用異常
58.對可恢復的情況使用受檢異常,對編程錯誤使用運行時異常
JAVA提供了三種可拋出結構(throwable)
1.受檢的異常(checked exception)
2.運行時異常(run-time exception)
3.錯誤(error)
59.避免不必要地使用受檢的異常
60.優先使用標準的異常
61.拋出與抽象相對應的異常
62.每個方法拋出的異常都要有文檔
63.在細節信息中包含能捕獲失敗的信息
64.努力使失敗保持原子性
65.不要忽略異常
第10章 并發
66.同步訪問共享的可變數據
關鍵字synchronized可以保證在同一時刻,只有一個線程可以執行某一個方法,或者某一個代碼塊。
67.避免過度同步
68.executor和task優先于線程
69.并發工具優先于wait和notify
70.線程安全性的文檔化
71.慎用延遲初始化
72.不要依賴于線程調度器
73.避免使用線程組
第11章 序列化
74.謹慎地實現Serializable接口
代價
1.實現Serializable接口而付出的最大代價是,可改變性變低
2.增加了出現Bug和安全漏洞的可能性
3.隨著類發行新的版本,相關的測試負擔也增加了
75.考慮使用自定義的序列化形式
76.保護性地編寫readObject方法
77.對于實例控制,枚舉類型優先于readResolve
78.考慮用序列化代理代替序列化實例