Effective Java 2 讀書筆記 78條

第一條 考慮使用靜態(tài)工廠方法代替構(gòu)造器

優(yōu)勢(shì)

  1. 有名稱
  2. 不必每次調(diào)用的時(shí)候都創(chuàng)建一個(gè)對(duì)象
  3. 返回原返回類型的所有子類型的對(duì)象
  4. 在創(chuàng)建參數(shù)實(shí)例化的時(shí)候魏铅,他們使代碼變得更簡潔

缺點(diǎn)

  1. 類如果不含有共有的或者受保護(hù)的類構(gòu)造器嗤堰,就不能被子類化
  2. 他們與其他的靜態(tài)方法沒什么區(qū)別

第二條 遇到多個(gè)構(gòu)造器時(shí)要考慮用構(gòu)建器

構(gòu)造器參數(shù)多,個(gè)數(shù)多,則優(yōu)先使用 Builder 模式,構(gòu)建器比JavaBeans更加安全

public interface Builder<T> {
  public T build();
}

第三條 用私有構(gòu)造器火鶴枚舉類型強(qiáng)化singleton屬性

單元素的枚舉類型已經(jīng)成為實(shí)現(xiàn)Singleton的最佳方法

public enum Elvis {
  INSTANCE;
  public void leaveTheBuilding() {}
}

第四條 通過私有構(gòu)造器強(qiáng)化不可實(shí)例化的能力

超類也不能被實(shí)例化

public class UtilityClass {
  private UtilityClass() {
    throw new AssertionError();
  }
}

第五條 避免創(chuàng)建不必要的對(duì)象

  1. 避免重復(fù)創(chuàng)建相同的對(duì)象
  2. 優(yōu)先使用基本類型而不是裝箱基本類型
  3. 不要盲目覺得創(chuàng)建對(duì)象代價(jià)十分昂貴,使用對(duì)象池的特例:數(shù)據(jù)庫連接池灿里,否則沒必要?jiǎng)?chuàng)建對(duì)象池,會(huì)影響GC

第六條 消除過期的對(duì)象引用

  1. 常見的場景在與ArrayList程腹,刪除對(duì)象后需要把該索引位置置空匣吊。
  2. 監(jiān)聽器,其他回調(diào)

可使用 WeakHashMap 將鍵保持為弱引用

第七條 避免使用終結(jié)方法

終結(jié)方法通常是不可預(yù)測的寸潦,也是很危險(xiǎn)的嗎色鸳,一般情況下是不必要的。使用終結(jié)方法是很危險(xiǎn)的见转。

終結(jié)方法線程的優(yōu)先級(jí)比應(yīng)用程序線程的優(yōu)先級(jí)低很多

// 不保證 finalize 執(zhí)行
System.gc System.runFinaliaation
// 保證執(zhí)行
System.runFinalizersOnExit Runtime.runFinalizersOnExit

第八條 覆蓋 equals 時(shí)請(qǐng)遵守通用約定

  • 類是私有的或是包級(jí)私有的命雀,可以確定它的 equals 方法永遠(yuǎn)不會(huì)被調(diào)用。
    防止方法被調(diào)用的方法
     @Ovveride
     public boolean equals(Object o) {
       throw new AssertionError();
     }
    
equals 方法實(shí)現(xiàn)了等價(jià)關(guān)系
  • 自反性
  • 對(duì)稱性
  • 傳遞性
  • 一致性
    一般做法
@Override
public boolean equals(Object o) {
  if (o == this) {
    return true;
  }
  if (!(o instanceOf MyClass)) {
    return false;
  }
  MyClass class = (MyClass) o;
  // 比較各個(gè)域值
  ......
}

第九條 覆蓋 equals 時(shí)總要覆蓋 hashCode

Object 規(guī)范(JavaSE6)

  • 同一個(gè)對(duì)象多次調(diào)用必須一致斩箫,同一個(gè)程序多次執(zhí)行可以不一致
  • equals 相等吏砂,hashCode 必然要相等
  • hashCode 相同,equals 不一定相同

一個(gè)好的散列函數(shù)通常傾向于“為不同的對(duì)象產(chǎn)生不相等的散列碼”
如何計(jì)算:

  1. 把某個(gè)非零常熟值乘客,比如說17狐血,保存到一個(gè)名為 result 的 int 類型的變量中。
  2. 對(duì)于對(duì)象中每個(gè)關(guān)鍵域 f (指 equals 方法中涉及到的每個(gè)域)易核,完成以下步驟:
    a. 為該域計(jì)算 int 類型的散列碼 c :
    • 如果該域是 boolean 類型氛雪,則計(jì)算 (f ? 1 : 0)
    • 如果該域是 byte ,char耸成,short,int浴鸿,則計(jì)算 (int)f
    • 如果該域是 long井氢,則計(jì)算(int)(f ^ (f >> 32))
    • 如果該域是 float,則計(jì)算 Float.floatToIntBits(f);
    • 如果該域是 double岳链,則計(jì)算 Double.doubleToLongBits(f), 然后按照步驟 a.3花竞,計(jì)算 long 的散列值
    • 如果該域是一個(gè)對(duì)象引用,并且該類的 equals 方法通過遞歸的調(diào)用 equals 的方式來比較這個(gè)域,則同樣為這個(gè)域遞歸的調(diào)用 hashCode约急。如果這個(gè)域?yàn)?null零远, 則為 0
    • 如果該域是一個(gè)數(shù)組,則需要把每一個(gè)元素當(dāng)作單獨(dú)的域來處理厌蔽。

b. 按照下面的公式牵辣,把步驟2.a 中計(jì)算得到的散列碼 c 合并到 result 中:
result = 31 * result + c;

  1. 返回 result
  2. check

第十條 始終要覆蓋 toString

建議所有的子類都應(yīng)該覆蓋這個(gè)方法

第十一條 謹(jǐn)慎的覆蓋 clone

創(chuàng)建和返回該對(duì)象的一個(gè)拷貝奴饮,不必調(diào)用構(gòu)造器創(chuàng)建對(duì)象
JavaSE6 的約定內(nèi)容:

  • x.clone() != x 為 true
  • x.clone().getClass() == x.getClass() 為 true
  • x.clone().equals(x) 為 true
    一般寫法纬向,通過遞歸 super.clone() 創(chuàng)建對(duì)象,再將域逐個(gè)復(fù)制即可

第十二條 考慮實(shí)現(xiàn) Comparable 接口

實(shí)現(xiàn)了 Comparable 接口戴卜,就表明它的實(shí)例具有內(nèi)在的排序關(guān)系逾条。
當(dāng)然,也可以使用外在排序 Comparator

第十三條 使類和成員的可訪問性最小化

設(shè)計(jì)良好的模塊會(huì)隱藏所有的實(shí)現(xiàn)細(xì)節(jié)投剥,把它的API與它的實(shí)現(xiàn)清晰的隔離開來师脂。

  • 盡可能地使每個(gè)類或成員不被外界訪問
  • 有四種訪問性:
    • 私有的(private)
    • 包級(jí)私有的(default)
    • 受保護(hù)的(protected)
    • 共有的(public)
      實(shí)例域不能是共有的

第十四條 在共有類中使用訪問方法而非共有域

有時(shí)候,可能會(huì)編寫一些退化類江锨,沒有什么作用吃警,只是用來集中實(shí)例域
Java平臺(tái)類庫中有一些違反了,但應(yīng)該警惕
共有類永遠(yuǎn)不應(yīng)該暴露可變的域

第十五條 使可變性最小化

不可變類只是其實(shí)例不能被修改的類泳桦。每個(gè)實(shí)例中包含的所有信息都必須在創(chuàng)建該實(shí)例的時(shí)候就提供汤徽,并在對(duì)象的整個(gè)生命周期內(nèi)固定不變,Java 平臺(tái)類庫中包含了許多不可變類灸撰,比如 String谒府,基本類型包裝類,BigDecimal 和 BigInteger浮毯。存在不可變的類有很多理由:不可變的類比可變的類更加容易設(shè)計(jì)完疫,實(shí)現(xiàn)和使用。
原則

  • 不要提供任何會(huì)修改對(duì)象狀態(tài)的方法
  • 保證類不會(huì)被擴(kuò)展
  • 使所有的域都是 final 的
  • 使所有的域都是私有的
  • 確保對(duì)于任何可變組件的互斥訪問

第十六條 復(fù)合優(yōu)先于繼承

繼承雖然是實(shí)現(xiàn)代碼重用的有力手段债蓝,但它會(huì)打破封裝性壳鹤。而復(fù)合可以解決這個(gè)問題,只有當(dāng)子類是超類的子類型時(shí)饰迹,才適用繼承(is-a關(guān)系)芳誓。Java 平臺(tái)類庫中 Stack和Vector,Properties和Hashtable 違反了這個(gè)原則

第十七條 要么為繼承而設(shè)計(jì)啊鸭,并提供文檔說明锹淌,要么就禁止繼承

對(duì)于專門為了繼承而設(shè)計(jì)的類需要具有良好文檔說明,該文檔必須精確的描述覆蓋每個(gè)方法所帶來的影響

  • 構(gòu)造器絕不能調(diào)用可被覆蓋的方法

第十八條 接口優(yōu)于抽象類

Java 程序設(shè)計(jì)語言提供了兩種機(jī)制赠制,可以用來定義允許多個(gè)實(shí)現(xiàn)的類型:接口和抽象

  • 現(xiàn)有的類很容易被更新赂摆,以實(shí)現(xiàn)新的借口
  • 接口是定義mixin(混合類型)的理想選擇
  • 接口允許我們構(gòu)造非層次結(jié)構(gòu)的類型框架

第十九條 接口只用于定義類型

接口應(yīng)該只被用來定義類型,不應(yīng)該被用來導(dǎo)出常量
導(dǎo)出常量的做法:

public class PhysicalConstants  {
  //  私有
  private PhysicalConstants() {}
  public static final double AVOGADROS_NUMBER = 6.02214199e23;
}

第二十條 類層次優(yōu)先于標(biāo)簽類

標(biāo)簽類使得類變得復(fù)雜難懂,考慮使用類層次替換
域是不能做成 final 的

第二十一條 用函數(shù)對(duì)象表示策略

簡而言之烟号,函數(shù)指針的主要用途就是實(shí)現(xiàn)策略模式绊谭。為了在 Java 中實(shí)現(xiàn)這種模式,要聲明一個(gè)接口來表示該策略汪拥,并且為每個(gè)具體的策略聲明實(shí)現(xiàn)一個(gè)該接口的類达传。當(dāng)一個(gè)具體策略只被使用一次的時(shí)候,通常使用匿名類的方式和實(shí)例化這個(gè)具體策略類喷楣。當(dāng)一個(gè)具體策略是設(shè)計(jì)用來重復(fù)使用的時(shí)候趟大,他的類通常就要實(shí)現(xiàn)為私有的靜態(tài)成員類,并通過共有的靜態(tài)final域被導(dǎo)出铣焊,其類型為該策略接口逊朽。

第二十二條 優(yōu)先考慮靜態(tài)成員類

嵌套類被定義為在另外一個(gè)類的內(nèi)部的類,有四種:靜態(tài)成員類曲伊,非靜態(tài)成員類叽讳,匿名類,局部類坟募,后三者為內(nèi)部類岛蚤;

第二十三條 請(qǐng)不要在新代碼中使用原生態(tài)類型

例如,List 原生態(tài)類型不能再編譯器發(fā)現(xiàn)類型轉(zhuǎn)化錯(cuò)誤懈糯,而使用范型則可以涤妒,更加安全

第二十四條 消除非受檢警告

第二十五條 列表優(yōu)先于數(shù)組

第二十六條 優(yōu)先考慮范型

不能創(chuàng)建范型數(shù)組

第二十七條 優(yōu)先考慮范型方法

public static <T entends Comparable<T>> T max(List<T> list) {
  Iterator<T> i = list.iterator();
  T result = i.next();
  while (i.hasNext()) {
    T t = i.next();
    if (t.compareTo(result) > 0) {
      result = t'
    }
  }
}

第二十八條 利用有限通配符來提升API的靈活性

第二十九條 優(yōu)先考慮類型安全的異構(gòu)容器

第三十條 用 enum 代替 int

第三十一條 用實(shí)例域代替序數(shù)

第三十二條 用 EnumSet 代替位域

第三十三條 用EnumMap 代替序數(shù)索引

第三十四條 用接口模擬可伸縮的枚舉

雖然無法編寫可擴(kuò)展的枚舉類型,卻可以通過編寫接口以及實(shí)現(xiàn)該接口的基礎(chǔ)枚舉類型赚哗,對(duì)它進(jìn)行模擬她紫。

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; }
  }
  private final String symbol;
  BasicOperation(String symbol) {
    this.symbol = symbol;
  }
}

第三十五條 注解優(yōu)先于命名模式

命名模式指的是:給一些類或者方法使用有特定約束的名字

第三十六條 堅(jiān)持使用 Override 注解

堅(jiān)持使用 Override 注解能夠避免一些錯(cuò)誤

第三十七條 用標(biāo)記接口定義類型

標(biāo)記接口是沒有包含任何方法的接口,例如 Serializable 接口屿储,不包含任何方法

第三十八條 檢查參數(shù)的有效性

對(duì)于共有的可以使用 throws 說明方法會(huì)產(chǎn)生什么異常
對(duì)于私有的方法可以使用 assert 斷言
簡而言之贿讹,每當(dāng)編寫方法或者構(gòu)造器的時(shí)候,應(yīng)該考慮它的參數(shù)有哪些限制够掠。應(yīng)該把這些限制寫到文檔中民褂,并且在這個(gè)方法提開頭處,通過顯式的檢查來實(shí)施這些限制疯潭。

第三十九條 必要時(shí)進(jìn)行保護(hù)性拷貝

簡而言之赊堪,如果類具有從客戶端得到或者返回客戶端的可變組件,類就必須保護(hù)性地拷貝這些組件竖哩。如果拷貝的成本受到限制雹食,并且類信任它的客戶端不會(huì)不恰當(dāng)?shù)男薷慕M件,就可以在文檔中指明客戶端的職責(zé)是不得修改受到影響的組件期丰,以此來代替保護(hù)性拷貝

第四十條 謹(jǐn)慎設(shè)計(jì)方法簽名

  • 謹(jǐn)慎的選擇方法的名稱
  • 不要過于追求提供便利的方法
  • 避免過長的參數(shù)列表

第四十一條 慎用重載

安全而保守的策略是,永遠(yuǎn)不要導(dǎo)出兩個(gè)具有相同參數(shù)樹木的重載方法

第四十二條 慎用可變參數(shù)

第四十三條 返回零長度的數(shù)組或者集合,而不是null

返回類型為 List 或數(shù)組钝荡,長度為零是返回 Collections.empty();

第四十四條 為所有導(dǎo)出的API元素編寫文檔注釋

第四十五條 將局部變量的作用域最小化

第四十六條 for-each 循環(huán)優(yōu)先于傳統(tǒng)的for循環(huán)

第四十七條 了解和使用類庫

第四十八條 如果需要精確的答案街立,請(qǐng)避免使用 float 和 double

第四十九條 基本類型優(yōu)先于裝箱基本類型

第五十條 如果其他類型更合適,則盡量避免使用字符串

第五十一條 當(dāng)心字符串連接的性能

第五十二條 通過接口引用對(duì)象

應(yīng)該優(yōu)先使用接口而不是類來引用對(duì)象

第五十三條 接口優(yōu)先于反射機(jī)制

第五十四條 謹(jǐn)慎的使用本地方法

第五十五條 謹(jǐn)慎的使用優(yōu)化

第五十六條 遵守普遍接受的命名習(xí)慣

第五十七條 只有針對(duì)異常的情況才使用異常

第五十八條 對(duì)可恢復(fù)的情況使用受檢異常埠通,對(duì)編程錯(cuò)誤使用運(yùn)行時(shí)異常

第五十九條 避免不必要地使用受檢的異常

第六十條 優(yōu)先使用標(biāo)準(zhǔn)的異常

第六十一條 拋出與抽象相對(duì)應(yīng)的異常

第六十二條 每個(gè)方法拋出的異常都要有文檔

第六十三條 在細(xì)節(jié)消息中包含能捕獲失敗的消息

第六十四條 努力是失敗保持原子性

第六十五條 不要忽略異常

第六十六條 同步訪問共享的可變數(shù)據(jù)

第六十七條 避免過度同步

第六十八條 executor 和 task 優(yōu)先于線程

第六十九條 并發(fā)工具優(yōu)先于 wait 和 notify

第七十條 線程安全性的文檔化

第七十一條 慎用延遲初始化

第七十二條 不要依賴于線程調(diào)度器

第七十三條 避免使用線程組

第七十四條 謹(jǐn)慎地實(shí)現(xiàn) Serializble 接口

實(shí)現(xiàn) Serializable 接口而付出第最大代價(jià)是赎离,一旦一個(gè)類被發(fā)布,就大大降低了“改變這個(gè)類的實(shí)現(xiàn)” 的靈活性

第七十五條 考慮使用自定義的序列化形式

第七十六條 保護(hù)性的編寫 readObject 方法

第七十七條 對(duì)于實(shí)例控制端辱,枚舉類型優(yōu)先于 readResolve

第七十八條 考慮使用序列化代理代替序列化實(shí)例

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末梁剔,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子舞蔽,更是在濱河造成了極大的恐慌荣病,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渗柿,死亡現(xiàn)場離奇詭異个盆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)朵栖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門颊亮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人陨溅,你說我怎么就攤上這事终惑。” “怎么了门扇?”我有些...
    開封第一講書人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵雹有,是天一觀的道長。 經(jīng)常有香客問我悯嗓,道長件舵,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任脯厨,我火速辦了婚禮铅祸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘合武。我一直安慰自己临梗,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開白布稼跳。 她就那樣靜靜地躺著盟庞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪汤善。 梳的紋絲不亂的頭發(fā)上什猖,一...
    開封第一講書人閱讀 52,196評(píng)論 1 308
  • 那天票彪,我揣著相機(jī)與錄音,去河邊找鬼不狮。 笑死降铸,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的摇零。 我是一名探鬼主播推掸,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼驻仅!你這毒婦竟也來了谅畅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤噪服,失蹤者是張志新(化名)和其女友劉穎毡泻,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體芯咧,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牙捉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了敬飒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邪铲。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖无拗,靈堂內(nèi)的尸體忽然破棺而出带到,到底是詐尸還是另有隱情,我是刑警寧澤英染,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布揽惹,位于F島的核電站,受9級(jí)特大地震影響四康,放射性物質(zhì)發(fā)生泄漏搪搏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一闪金、第九天 我趴在偏房一處隱蔽的房頂上張望疯溺。 院中可真熱鬧,春花似錦哎垦、人聲如沸囱嫩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽墨闲。三九已至,卻和暖如春郑口,著一層夾襖步出監(jiān)牢的瞬間鸳碧,已是汗流浹背盾鳞。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留杆兵,地道東北人雁仲。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像琐脏,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子缸兔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

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

  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學(xué)習(xí)記錄文檔日裙,今天18年5月份再次想寫文章,發(fā)現(xiàn)簡書還為我保存起的...
    Jenaral閱讀 2,767評(píng)論 2 9
  • 目錄 第二章 創(chuàng)建和銷毀對(duì)象 1 考慮用靜態(tài)工廠方法替代構(gòu)造器 對(duì)于代碼來說, 清晰和簡潔是最重要的. 代碼應(yīng)該被...
    高廣超閱讀 1,454評(píng)論 0 12
  • 《Effective Java》讀書筆記目錄惰蜜,這篇文章記錄了我讀這本書的一些想法和驗(yàn)證昂拂。 1. 考慮用靜態(tài)工廠方法...
    noexceptionsir閱讀 1,670評(píng)論 0 2
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法抛猖,內(nèi)部類的語法格侯,繼承相關(guān)的語法,異常的語法财著,線程的語...
    子非魚_t_閱讀 31,660評(píng)論 18 399
  • 鷹派與鴿派代表了兩種不同的性格取向撑教,對(duì)于每個(gè)人來說這兩種性格的取向都是占有一部分的朝墩,只是每個(gè)人的比例不同。鷹派取向...
    你好_630f閱讀 1,858評(píng)論 0 0