第二章 創(chuàng)建和銷毀對(duì)象
1、靜態(tài)工廠代替構(gòu)造器
- 避免每次都創(chuàng)建對(duì)象
- 可返回任何子類型對(duì)象
- .from .of .valueOf .create .instance .type 有不同的含義
2茶鹃、遇到多個(gè)構(gòu)造器參數(shù)是要考慮使用構(gòu)構(gòu)建器
- 所有屬性進(jìn)行set,在構(gòu)造過程中可能導(dǎo)致不一致狀態(tài)出現(xiàn)
- 建造者模式蕉汪,屬性final流译,加一個(gè)靜態(tài)成員類
3、用私有構(gòu)造器或枚舉類型強(qiáng)化Singleton
4者疤、通過私有構(gòu)造器強(qiáng)化不可實(shí)例化能力
5福澡、優(yōu)先考慮依賴注入引用資源
- 不通過單例和靜態(tài)工具類來實(shí)現(xiàn)依賴一個(gè)或多個(gè)底層資源類
- 將這些資源或工廠傳給構(gòu)造器,通過他們創(chuàng)建類
6驹马、避免創(chuàng)建不必要的對(duì)象
- 優(yōu)先使用基本類型而不是裝箱類型
7革砸、消除過期的對(duì)象引用
- 棧pop掉的元素不會(huì)被垃圾回收
- 一旦對(duì)象引用已經(jīng)過期,只需清空這些引用糯累,pop的時(shí)候加個(gè)
element[size] = null
8算利、避免使用終結(jié)方法和清除方法
- 不能保證被及時(shí)執(zhí)行
9、try-with-resources優(yōu)先于try-final
第三章 對(duì)于所有對(duì)象都通用的方法
10泳姐、覆蓋equals時(shí)遵守通用約定
- 自反性
- 對(duì)稱性
- 傳遞性
- 一致性
- 非null equals null必須返回false
- 使用==檢查參數(shù)是否胃這個(gè)對(duì)象的引用
- 使用instanceof操作檢查參數(shù)是否為正確類型
- 參數(shù)轉(zhuǎn)換成正確類型
- 對(duì)于該類中的每個(gè)關(guān)鍵域效拭,檢查參數(shù)中的域是否域該對(duì)象中對(duì)應(yīng)的域相匹配
- 覆蓋equals時(shí)總要覆蓋hashCode
- 不要企圖讓equals方法過于智能
- 不要將equals聲明中的Object對(duì)象替換為其他類型,替換了就不是覆蓋時(shí)重載了
11、覆蓋equals時(shí)總要覆蓋hashCode
- 相等的對(duì)象必須具有相等的散列碼
- 如果一個(gè)類是不可變的缎患,計(jì)算散列碼開銷大借笙,就考慮把散列碼緩存在對(duì)象內(nèi)部
12、始終覆蓋toString
13较锡、謹(jǐn)慎地覆蓋clone
- clone业稼,無須調(diào)用構(gòu)造器就可以創(chuàng)建對(duì)象
- 需要逐域clone,只super.clone有可能導(dǎo)致部分引用的可變域沒被clone最后出錯(cuò)
- clone方法不應(yīng)該在構(gòu)造過程中蚂蕴,調(diào)用可覆蓋的方法
14低散、考慮實(shí)現(xiàn)Comparable接口
第四章 類和接口
15、使類和成員的可訪問性最小化
16骡楼、在公有類中使用訪問方法而非公有域
17熔号、使可變性最小化
- 不可變的類比可變類更加易于設(shè)計(jì)、實(shí)現(xiàn)和使用
- 不要提供任何會(huì)修改對(duì)象狀態(tài)的方法
- 保證類不會(huì)被擴(kuò)展
- 聲明所有的域都是final
- 聲明所有域都是私有
- 確保對(duì)于任何可變組件互斥訪問鸟整,如果類具有指向可變對(duì)象的域引镊,則必須確保該類的客戶端無法獲得指向這些對(duì)象的引用
18、復(fù)合優(yōu)先于繼承
19篮条、要么設(shè)計(jì)繼承并提供文檔說明弟头,要么禁止繼承
下面的例子,super調(diào)用父類構(gòu)造器涉茧,override調(diào)用子類的赴恨,但是此時(shí)還未完成初始化
無論是clone還是readObject,都不可以調(diào)用可覆蓋的方法伴栓,不管是直接還是間接伦连。覆蓋的方法將在子類被序列化或是修正克隆對(duì)象狀態(tài)之前運(yùn)行,就得不到想要的結(jié)果钳垮。
20惑淳、接口優(yōu)于抽象類
- 接口允許構(gòu)造非層次類型的框架
- 通過對(duì)接口提供一個(gè)抽象的股價(jià)實(shí)現(xiàn),可以把接口和抽象類的有點(diǎn)結(jié)合起來饺窿。
21歧焦、為后代設(shè)計(jì)接口
- 有缺省方法后,如果沒實(shí)現(xiàn)也不會(huì)報(bào)錯(cuò)
22短荐、接口只用于定義類型
- 用枚舉定義常量
23倚舀、類層次優(yōu)于標(biāo)簽類
24、靜態(tài)成員類優(yōu)于非靜態(tài)成員類
- 靜態(tài)成員類忍宋,公有類的輔助類痕貌,只有和外部類一起使用才有意義。
- 非靜態(tài)成員類糠排,每個(gè)實(shí)例都隱含地與外圍類的一個(gè)外圍實(shí)例相關(guān)聯(lián)舵稠。可以調(diào)用外圍實(shí)例上的方法。如果聲明成員類不要求訪問外圍實(shí)例哺徊,就要始終把修飾符static放在它的聲明中室琢。引用是會(huì)有成本的。
- 匿名類落追, lambda表達(dá)式
- 局部類
25盈滴、限制源文件為單個(gè)頂級(jí)類
第五章 泛型
26、請(qǐng)不要使用原生態(tài)類型
- 主要是針對(duì)容器轿钠,需要指定類型
27巢钓、消除非受檢的警告
- 非受檢轉(zhuǎn)換之類的
28、列表優(yōu)于數(shù)組
- 數(shù)組是協(xié)變的疗垛,類型有父子關(guān)系
- 泛型是可變的
- 數(shù)組和泛型不能很好地混合使用
29症汹、優(yōu)先考慮泛型
30、優(yōu)先考慮泛型方法
31贷腕、利用有限制通配符來提升API的靈活性
- 生產(chǎn)者用<? extends T>背镇;消費(fèi)者用<? super T>
32、謹(jǐn)慎并用泛型和可變參數(shù)
static void f(List<String>... stringLists) {
List<Integer> intList = List.of(42);
Object[] objects = stringLists;
object[0] = intList; // Heap pollution;
String s = stringLists[0].get(0);
}
33泽裳、優(yōu)先考慮類型安全的異構(gòu)容器
- 一個(gè)容器存儲(chǔ)多種類型瞒斩,可以把key變成 Class對(duì)象,實(shí)現(xiàn)異構(gòu)
第6章 枚舉和注解
34诡壁、用enum代替int常量
- 枚舉類型沒有可以訪問的構(gòu)造器济瓢,所以它是真正的final類
35、用實(shí)例域代替序數(shù)
- 給枚舉加實(shí)例域而不是用自帶的序數(shù)
36妹卿、用EnumSet代替位域
37、用EnumMap代替序數(shù)索引
38蔑鹦、用接口模擬可擴(kuò)展的枚舉
public interface Operation {
double apply(double x, double y);
}
public enum BasicOperation implements Operation {
PLUS("+") {
public double apply(double x, double y) {return x + y;}
}
}
39夺克、注解優(yōu)先于明明模式
40、堅(jiān)持使用Override注解
41嚎朽、用標(biāo)記接口定義類型
- 沒有方法的接口铺纽,只用于標(biāo)明一個(gè)類實(shí)現(xiàn)了具有某種屬性的接口
第7章 Lambda和Stream
42、Lambda優(yōu)先于匿名類
- 匿名類可以獲得對(duì)自身的引用哟忍,但是lambda不行
43狡门、方法引用優(yōu)先于Lambda
44、堅(jiān)持使用標(biāo)準(zhǔn)函數(shù)接口
UnaryOperator<T>
BinaryOperator<T>
Predicate<T>
Function<T,R>
Supplier<T>
Consumer<T>
45锅很、謹(jǐn)慎使用Stream
- 從代碼塊中可以讀取或修改范圍內(nèi)的任意局部變量其馏,lambda則只能讀取final或有效的final變量
- 從代碼塊中可以從外圍方法中跳出循環(huán)
- Stream一旦將一個(gè)值映射到某個(gè)其他值,原來的值就丟失了
46爆安、優(yōu)先選擇Stream中無副作用的函數(shù)
47叛复、Stream要優(yōu)先用Collection作為返回類型
- Collection接口是Iterabale的一個(gè)子類型,它有一個(gè)stream方法,因此提供了迭代和stream訪問
48褐奥、謹(jǐn)慎使用Stream并行
- 最好進(jìn)行精確的子范圍劃分再進(jìn)行處理
第8章 方法
49咖耘、檢查參數(shù)的有效性
50、必要時(shí)進(jìn)行保護(hù)性拷貝
51撬码、謹(jǐn)慎設(shè)計(jì)方法簽名
- 參數(shù)應(yīng)當(dāng)四個(gè)或更少
- 不要過于追求提供便利的方法
52儿倒、慎用重載
- 重載方法的選擇是靜態(tài)的,覆蓋方法的選擇是動(dòng)態(tài)的
- 安全而保守的策略是永遠(yuǎn)不要導(dǎo)出兩個(gè)具有相同參數(shù)數(shù)目的重載方法
53呜笑、慎用可變參數(shù)
54义桂、返回零長(zhǎng)度的數(shù)組或集合而不是null
55、謹(jǐn)慎返回optional
- 永遠(yuǎn)不要通過返回Optional的方法返回null
56蹈垢、為所有導(dǎo)出的API元素編寫文檔注釋
第9章 通用編程
57慷吊、局部變量的作用域最小化
58、for-each循環(huán)優(yōu)先于傳統(tǒng)for循環(huán)
- 完全隱藏迭代器或索引變量曹抬,避免了混亂和出錯(cuò)的可能掌逛。
59眷细、了解和使用類庫
60、如果需要精確地答案,避免使用float和double
61役首、基本類型優(yōu)先于裝箱基本類型
- 對(duì)裝箱基本類型運(yùn)用==幾乎總是錯(cuò)誤的。
- 反復(fù)裝箱會(huì)導(dǎo)致明顯的性能下降笨枯。
62瘟滨、如果其他類型更合適,則盡量避免使用字符串
- 可能造成無意的共享为牍。
63哼绑、了解字符串連接的性能
- 連接n個(gè)字符串而重復(fù)使用字符串連接操作,需要n的平方級(jí)時(shí)間碉咆,內(nèi)容需要被拷貝抖韩。
- 使用StringBuilder代替String
64、通過接口引用對(duì)象
- 如果沒有合適的接口疫铜,就用類層次結(jié)構(gòu)中提供了必要功能的最小的具體類來引用對(duì)象茂浮。
65、接口優(yōu)先于反射機(jī)制
66壳咕、謹(jǐn)慎地使用本地方法
67席揽、謹(jǐn)慎地進(jìn)行優(yōu)化
- 要努力避免那些先知性能的設(shè)計(jì)決策,最主要的是API谓厘、交互層協(xié)議以及永久數(shù)據(jù)格式幌羞。
- 要考慮API設(shè)計(jì)決策的性能后果。
68庞呕、遵守普遍接受的命名習(xí)慣
第10章 異常
69新翎、只針對(duì)異常的情況才使用異常
- 如果類具有狀態(tài)相關(guān)的方法程帕,即只有在特定的不可預(yù)知的條件下才可以被調(diào)用的方法,這個(gè)類往往也應(yīng)該有個(gè)單獨(dú)的狀態(tài)測(cè)試地啰。
70愁拭、對(duì)可恢復(fù)的情況使用受檢異常,對(duì)編程錯(cuò)誤使用運(yùn)行時(shí)異常
71亏吝、避免不必要地使用受檢異常
- 消除受檢異常最容易的方法是岭埠,返回所要得結(jié)果類型的一個(gè)optional
72、優(yōu)先使用標(biāo)準(zhǔn)異常
73蔚鸥、拋出與抽象對(duì)應(yīng)的異常
- 更高層的實(shí)現(xiàn)應(yīng)該捕獲低層的異常惜论,同時(shí)拋出可以按照高層抽象進(jìn)行解釋的異常。
74止喷、每個(gè)方法拋出的所有異常都要建立文檔
75馆类、在細(xì)節(jié)消息中包含失敗-捕獲信息
- 異常的細(xì)節(jié)信息應(yīng)該包含對(duì)該異常有貢獻(xiàn)的所有參數(shù)和域的值
76、努力使失敗保持原子性
- 使對(duì)象保持在被調(diào)用之前的狀態(tài)
- 獲得失敗原子性最常見的辦法是在執(zhí)行操作之前檢查參數(shù)的有效性
public Object pop() {
if (size == 0) throw new EmptyStackException();
}
77弹谁、不要忽略異常
第11章 并發(fā)
78乾巧、同步訪問共享的可變數(shù)據(jù)
- 除非讀和寫操作都被同步,否則無法保證同步能起作用
79预愤、避免過度同步
- 在一個(gè)被同步的區(qū)域內(nèi)部沟于,不要調(diào)用設(shè)計(jì)成要被覆蓋的方法,或者是由客戶端以函數(shù)對(duì)象形式提供的方法植康。
- 應(yīng)該在同步區(qū)域內(nèi)做盡可能少的工作旷太。
- 過度同步的實(shí)際成本并不是指獲取鎖所花費(fèi)的CPU時(shí)間,而是指失去了并行的機(jī)會(huì)销睁。
- 為了避免死鎖和數(shù)據(jù)破壞供璧,千萬不要從同步區(qū)域內(nèi)部調(diào)用外來方法。
80榄攀、executor嗜傅、task和stream優(yōu)先于線程
- Thread是既充當(dāng)工作單元,又是執(zhí)行機(jī)制檩赢。在Executor Framework中,工作單元和執(zhí)行機(jī)制是分開的违寞。工作單元贞瞒,稱為task。任務(wù)有兩種Runnable和Callable趁曼。執(zhí)行任務(wù)的通用機(jī)制是executor service军浆。
81、并發(fā)工具優(yōu)先于wait和notify
82挡闰、線程安全性的文檔化
- lock域應(yīng)該始終聲明為final
- 避免拒絕服務(wù)供給乒融,可以使用私有鎖對(duì)象來代替同步方法
private final object lock = new Object();
public void foo() {
synchronized(lock) {
}
}
83掰盘、慎用延遲初始化
- 在大多數(shù)情況下,正常的初始化要優(yōu)先于延遲初始化
- 如果要對(duì)靜態(tài)域使用延遲初始化赞季,就使用lazy initializaition holder class
private static class FieldHolder {
static final FieldType field = computeFieldValue();
}
private static FieldTpe getField() {
return FieldHolder.field;
}
- 如果要對(duì)實(shí)例域使用延遲初始化愧捕,就使用雙重檢查模式
private volatile FieldType field;
private FieldType getField() {
FieldType result = field;
if (result == null) {
synchronized(this) {
if (field == null) field = result = computeFieldValue();
}
}
}
84、不要依賴于線程調(diào)度器
- 如果線程沒有在做有意義的工作申钩,就不應(yīng)該運(yùn)行次绘。
- 任何依賴于線程調(diào)度器來達(dá)到正確性或者性能要求的程序,很有可能是不可移植的撒遣。
第12章 序列化
85邮偎、其他方法優(yōu)先于Java序列化
- 避免序列化供給的最佳方式是永遠(yuǎn)不要反序列化任何東西。
- 永遠(yuǎn)不要反序列化不被信任的數(shù)據(jù)义黎。
86禾进、謹(jǐn)慎地實(shí)現(xiàn)Serializable接口
- 如果沒有聲明一個(gè)顯式的序列版本UID,兼容性將會(huì)遭到破壞廉涕。
- 如果一個(gè)類實(shí)現(xiàn)了Serializable接口泻云,它的字節(jié)流編碼就變成了它的導(dǎo)出的API的一部分。
- 內(nèi)部類不應(yīng)該實(shí)現(xiàn)Serializable接口火的。
87壶愤、考慮使用自定義的序列化形式
- 默認(rèn)的序列化形式描述了該對(duì)象內(nèi)部所包含的數(shù)據(jù)以及每一個(gè)可以從這個(gè)對(duì)象到達(dá)的其他對(duì)象的內(nèi)部數(shù)據(jù)。
- 使用默認(rèn)序列化形式會(huì)消耗過多空間馏鹤、時(shí)間征椒,會(huì)引起棧溢出等問題。
- 如果在讀取整個(gè)對(duì)象狀態(tài)的任何其他方法上強(qiáng)制任何同步湃累,則也必須在對(duì)象序列化上強(qiáng)制這種同步勃救。
88、保護(hù)性地編寫readObject方法
- readObject方法實(shí)際上相當(dāng)于另一個(gè)公有構(gòu)造器
- 偽造字節(jié)流可能通過反序列化實(shí)現(xiàn)攻擊
- 對(duì)于對(duì)象引用域必須保持為私有的類治力,要保護(hù)性地拷貝這些域中的每個(gè)對(duì)象蒙秒。如果檢查失敗,則拋出一個(gè)InvalidObjectException宵统。
89晕讲、對(duì)于實(shí)例控制,枚舉類型優(yōu)先于readResolve
- 如果單例包含一個(gè)非瞬時(shí)的對(duì)象引用域马澈,這個(gè)域的內(nèi)容就可以在單例的readResolve方法運(yùn)行之前被反序列化
90瓢省、考慮用序列化代理代替序列化實(shí)例
- 為可序列化的類設(shè)計(jì)一個(gè)私有的靜態(tài)嵌套類,有一個(gè)單獨(dú)的構(gòu)造器痊班,其參數(shù)類型就是外圍類勤婚。這個(gè)構(gòu)造器只從它的參數(shù)中復(fù)制數(shù)據(jù)
private static class SerializationProxy implements Serializable {
private final Date start;
private final Date end;
SerializationProxy(Period p) {
this.start = p.start;
this.end = p.end;
}
private Object writeReplace() { return new SerializationProxy(this); }
}