《Effective Java》做者是美國的Joshua Bloch,連Gosling都說須要看的書,討論的是更深層次的Java開發技術,適合於有必定Java基礎的人看。html
這是一本分享經驗於指引您少走彎路的經典著做,針對如何編寫高效、設計優良的程序提出了最實用的方針。程序員
Item1 考慮用靜態工廠方法代替構造器數組
一、優勢緩存
可讀性強。安全
不會每次調用就經過構造器建立一個新的實例。工具
能夠返回原始類型的任何子類型。性能
二、缺點ui
只有私有構造器沒法被子類化。this
Item 2 遇到多個構造器參數考慮用構建器Builderspa
一、傳統的重疊構造器模式
public class NutritionFacts { private final int servingSize; // (mL) required private final int servings; // (per container) required private final int calories; // (per serving) optional private final int fat; // (g/serving) optional private final int sodium; // (mg/serving) optional private final int carbohydrate; // (g/serving) optional public NutritionFacts(int servingSize, int servings) { this(servingSize, servings, 0); } public NutritionFacts(int servingSize, int servings, int calories) { this(servingSize, servings, calories, 0); } public NutritionFacts(int servingSize, int servings, int calories, int fat) { this(servingSize, servings, calories, fat, 0); } public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium) { this(servingSize, servings, calories, fat, sodium, 0); } public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium, int carbohydrate) { this.servingSize = servingSize; this.servings = servings; this.calories = calories; this.fat = fat; this.sodium = sodium; this.carbohydrate = carbohydrate; } public static void main(String[] args) { NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27); } }
若是讀者想了解那些值是什麼意思,必須很費勁的仔仔細細的數着這些參數來探究。若是客戶端不當心顛倒了這些參數的順序,編譯器也不會報錯,可是程序在運行時會出現錯誤行爲。
JavaBeans模式
public class NutritionFacts { // Parameters initialized to default values (if any) private int servingSize = -1; // Required; no default value private int servings = -1; // Required; no default value private int calories = 0; private int fat = 0; private int sodium = 0; private int carbohydrate = 0; public NutritionFacts() { } // Setters public void setServingSize(int val) { servingSize = val; } public void setServings(int val) { servings = val; } public void setCalories(int val) { calories = val; } public void setFat(int val) { fat = val; } public void setSodium(int val) { sodium = val; } public void setCarbohydrate(int val) { carbohydrate = val; } public static void main(String[] args) { NutritionFacts cocaCola = new NutritionFacts(); cocaCola.setServingSize(240); cocaCola.setServings(8); cocaCola.setCalories(100); cocaCola.setSodium(35); cocaCola.setCarbohydrate(27); } }
這樣實例建立很容易,客戶端代碼讀起來很清晰明朗,可是,程序員須要付出額外的努力來確保它的線程安全
Builder模式
public class NutritionFacts { private final int servingSize; private final int servings; private final int calories; private final int fat; private final int sodium; private final int carbohydrate; public static class Builder { // Required parameters private final int servingSize; private final int servings; // Optional parameters - initialized to default values private int calories = 0; private int fat = 0; private int sodium = 0; private int carbohydrate = 0; public Builder(int servingSize, int servings) { this.servingSize = servingSize; this.servings = servings; } public Builder calories(int val) { calories = val; return this; } public Builder fat(int val) { fat = val; return this; } public Builder sodium(int val) { sodium = val; return this; } public Builder carbohydrate(int val) { carbohydrate = val; return this; } public NutritionFacts build() { return new NutritionFacts(this); } } private NutritionFacts(Builder builder) { servingSize = builder.servingSize; servings = builder.servings; calories = builder.calories; fat = builder.fat; sodium = builder.sodium; carbohydrate = builder.carbohydrate; } public static void main(String[] args) { NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8) .calories(100).sodium(35).carbohydrate(27).build(); } }
builder設置方法返回this,造成了鏈式調用,這個一個流式的API,客戶端代碼很容易編寫,更爲重要的是易於閱讀。
二、使用構建器的好處。
在多參數時寫法優雅,參數具備可讀性,保證線程安全,適合類的繼承。
三、使用構建器的壞處。
花費會更高,所以在參數有許多的時候建議使用,特別是有不少可選參數時。
Item 3 Singleton的最佳實現方式是枚舉類型
一、什麼是枚舉類
public class EnumTest { public static void main(String[] args) { Scanner in=new Scanner(System.in); System.out.println("put:"); String input=in.next().toUpperCase(); Size size=Enum.valueOf(Size.class,input); System.out.println(size); System.out.println(size.getAbbreviation()); System.out.println(Size.SMALL.getAbbreviation()); } } enum Size{ SMALL("S"),MEDIUM("M"),LARGE("L"); private String abbreviation; private Size(String abbreviation){this.abbreviation=abbreviation;} public String getAbbreviation(){return abbreviation;} }
二、優勢
提供序列化機制,甚至在反射機制下也能確保只有單例。
三、缺點
沒法繼承自除了Enum以外的超類以及其餘子類進行繼承。
Item 4 經過私有構造器強化不可實例化的能力
一、優勢
在須要建立相似工具類等不須要實例化的類時,將構造器私有化,以保證該類在任何狀況下都不會被實例化。
二、缺點
沒法被繼承
Item 5 使用依賴注入去鏈接資源
一、依賴注入
public class dependency { private final String str; public dependency(String str) { this.str = str; } }
二、優勢
對於一個行爲由其餘資源所參數化所決定的類來講,使用靜態工具類或者單例是不適合的。而是應該當建立一個實例是將資源傳入構造器。
Item 6 避免建立沒必要要的對象
一、優勢
對於一些不會發生改變的變量或是常量,使用static塊進行初始化,使某些類不會被重複建立,減小開銷。例如 new String就是一個很差的習慣。
在構造器中使用靜態工廠就是個不錯的方法。重點是對靜態的使用static(final)。自動裝箱也極可能引發巨大的開銷。
Item 7消除過時的對象引用
一、優勢
例如對於Stack類中的數組當執行pop()操做後,被彈出的元素並不會自動被gc所回收。所以須要手動進行釋放。
public Object pop() { if (size == 0) throw new EmptyStackException(); Object result = elements[--size]; elements[size] = null; // Eliminate obsolete reference return result; }
當一個類本身進行內存的管理時,這種情況就尤爲要注意。
進行緩存時也須要注意這個問題。
對於監聽器以及回調操做,也須要注意。
Item 8 儘可能避免使用Finalizers
一、優勢
因爲Finalizers的優先級很低,不能保證Finalizers什麼時候會被調用,會致使內存開銷的增長,而且會大幅下降程序的性能。
永遠不要Finalizers來更新持久狀態。
對含有Finalizers方法的類進行子類化會有嚴重的安全隱患。
使用try-with-resources做爲某些資源的結束方法。而且對於其狀態是否被關閉須要在私有域中進行記錄。這樣其餘方法調用時能夠對狀態進行檢測。
Finalizers有兩種合理的用法:
一、在忘記調用close方法時做爲一張安全網,但這也只是一個不得以的備用措施,仍然會形成很大開銷,而且不知什麼時候會進行。
二、native peer (?)
Item 9 更偏向使用 try-with-resources 塊
一、try-with-resources
在try()中進行一個或多個的資源連接或讀取。而且這些資源是必須被關閉的的,使用這個語法將會被自動關閉無需顯示調用close方法。
在{}進行實際操做。
一樣可使用catch語句
static void copy(String src, String dst) throws IOException { try (InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dst)) { byte[] buf = new byte[BUFFER_SIZE]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } }
二、優勢
能夠同時打開多個資源,並保證被關閉,而無需顯式調用close方法。
exception不會被覆蓋,能夠查看每一個exception.
參考:《Effective Java》第3版
參考:https://www.cnblogs.com/WutingjiaWill/p/9139520.html