## Chapter 2. Creating and Destroying Objects(創建和銷毀對象)
### Item 2: Consider a builder when faced with many constructor parameters(當構造函數有多個參數時,考慮改用構建器)
Static factories and constructors share a limitation: they do not scale well to large numbers of optional parameters. Consider the case of a class representing the Nutrition Facts label that appears on packaged foods. These labels have a few required fields—serving size, servings per container, and calories per serving— and more than twenty optional fields—total fat, saturated fat, trans fat,cholesterol, sodium, and so on. Most products have nonzero values for only a few of these optional fields.
靜態工廠和構造函數都有一個局限:它們不能對大量可選參數做很好的擴展。以一個類為例,它表示包裝食品上的營養標簽。這些標簽上有一些字段是必需的,如:凈含量、毛重和每單位份量的卡路里,另有超過 20 個可選的字段,如:總脂肪、飽和脂肪、反式脂肪、膽固醇、鈉等等。大多數產品只有這些可選字段中的少數,且具有非零值。
What sort of constructors or static factories should you write for such a class?Traditionally, programmers have used the telescoping constructor pattern, in which you provide a constructor with only the required parameters, another with a single optional parameter, a third with two optional parameters, and so on,culminating in a constructor with all the optional parameters. Here’s how it looks in practice. For brevity’s sake, only four optional fields are shown:
應該為這樣的類編寫什么種類的構造函數或靜態工廠呢?傳統的方式是使用可伸縮構造函數,在這種模式中,只向構造函數提供必需的參數。即,向第一個構造函數提供單個可選參數,向第二個構造函數提供兩個可選參數,以此類推,最后一個構造函數是具有所有可選參數的。這是它在實際應用中的樣子。為了簡潔起見,只展示具備四個可選字段的情況:
```
// Telescoping constructor pattern - does not scale well!
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;
}
}
```
When you want to create an instance, you use the constructor with the shortest parameter list containing all the parameters you want to set:
當你想要創建一個實例時,可以使用包含所需參數的最短參數列表的構造函數:
```
NutritionFacts cocaCola =new NutritionFacts(240, 8, 100, 0, 35, 27);
```
Typically this constructor invocation will require many parameters that you don’t want to set, but you’re forced to pass a value for them anyway. In this case,we passed a value of 0 for fat. With “only” six parameters this may not seem so bad, but it quickly gets out of hand as the number of parameters increases.
通常,這個構造函數包含許多額外的參數,但是你必須為它們傳遞一個值。在本例中,我們為 fat 傳遞了一個值 0。只有六個參數時,這可能看起來不那么糟,但隨著參數的增加,它很快就會失控。
In short, **the telescoping constructor pattern works, but it is hard to write client code when there are many parameters, and harder still to read it.** The reader is left wondering what all those values mean and must carefully count parameters to find out. Long sequences of identically typed parameters can cause subtle bugs. If the client accidentally reverses two such parameters, the compiler won’t complain, but the program will misbehave at runtime (Item 51).
簡單地說,**可伸縮構造函數模式可以工作,但是當有很多參數時,編寫客戶端代碼是很困難的,而且讀起來更困難。** 讀者想知道所有這些值是什么意思,必須仔細清點參數。相同類型參數的長序列會導致細微的錯誤。如果客戶端不小心倒轉了兩個這樣的參數,編譯器不會報錯,但是程序會在運行時出錯([Item-51](/Chapter-8/Chapter-8-Item-51-Design-method-signatures-carefully.md))。
A second alternative when you’re faced with many optional parameters in a constructor is the JavaBeans pattern, in which you call a parameterless constructor to create the object and then call setter methods to set each required parameter and each optional parameter of interest:
當你在構造函數中遇到許多可選參數時,另一種選擇是 JavaBean 模式,在這種模式中,你調用一個無參數的構造函數來創建對象,然后調用 setter 方法來設置每個所需的參數和每個感興趣的可選參數:
```
// JavaBeans Pattern - allows inconsistency, mandates mutability
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; }
}
```
This pattern has none of the disadvantages of the telescoping constructor pattern.It is easy, if a bit wordy, to create instances, and easy to read the resulting code:
這個模式沒有可伸縮構造函數模式的缺點。創建實例很容易,雖然有點冗長,但很容易閱讀生成的代碼:
```
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);
```
Unfortunately, the JavaBeans pattern has serious disadvantages of its own. Because construction is split across multiple calls, a JavaBean may be in an inconsistent state partway through its construction. The class does not have the option of enforcing consistency merely by checking the validity of the constructor parameters. Attempting to use an object when it’s in an inconsistent state may cause failures that are far removed from the code containing the bug and hence difficult to debug. A related disadvantage is that the JavaBeans pattern precludes the possibility of making a class immutable (Item 17) and requires added effort on the part of the programmer to ensure thread safety.
不幸的是,JavaBean 模式本身有嚴重的缺點。因為構建是在多個調用之間進行的,所以 JavaBean 可能在構建的過程中處于不一致的狀態。該類不能僅通過檢查構造函數參數的有效性來強制一致性。在不一致的狀態下嘗試使用對象可能會導致錯誤的發生,而包含這些錯誤的代碼很難調試。一個相關的缺點是,JavaBean 模式排除了使類不可變的可能性([Item-17](/Chapter-4/Chapter-4-Item-17-Minimize-mutability.md)),并且需要程序員額外的努力來確保線程安全。
It is possible to reduce these disadvantages by manually “freezing” the object when its construction is complete and not allowing it to be used until frozen, but this variant is unwieldy and rarely used in practice. Moreover, it can cause errors at runtime because the compiler cannot ensure that the programmer calls the freeze method on an object before using it.
通過在對象構建完成時手動「凍結」對象,并在凍結之前不允許使用對象,可以減少這些缺陷,但是這種變通方式很笨拙,在實踐中很少使用。此外,它可能在運行時導致錯誤,因為編譯器不能確保程序員在使用對象之前調用它的 freeze 方法。
Luckily, there is a third alternative that combines the safety of the telescoping constructor pattern with the readability of the JavaBeans pattern. It is a form of the Builder pattern [Gamma95]. Instead of making the desired object directly,the client calls a constructor (or static factory) with all of the required parameters and gets a builder object. Then the client calls setter-like methods on the builder object to set each optional parameter of interest. Finally, the client calls a parameterless build method to generate the object, which is typically immutable. The builder is typically a static member class (Item 24) of the class itbuilds. Here’s how it looks in practice:
幸運的是,還有第三種選擇,它結合了可伸縮構造函數模式的安全性和 JavaBean 模式的可讀性。它是建造者模式的一種形式 [Gamma95]。客戶端不直接生成所需的對象,而是使用所有必需的參數調用構造函數(或靜態工廠),并獲得一個 builder 對象。然后,客戶端在構建器對象上調用像 setter 這樣的方法來設置每個感興趣的可選參數。最后,客戶端調用一個無參數的構建方法來生成對象,這通常是不可變的。構建器通常是它構建的類的靜態成員類([Item-24](/Chapter-4/Chapter-4-Item-24-Favor-static-member-classes-over-nonstatic.md))。下面是它在實際應用中的樣子:
**若將該案例「構建機制」獨立出來,或能廣泛適應相似結構的構建需求,詳見文末隨筆**
```
// Builder Pattern
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;
}
}
```
The NutritionFacts class is immutable, and all parameter default values are in one place. The builder’s setter methods return the builder itself so that invocations can be chained, resulting in a fluent API. Here’s how the client code looks:
NutritionFacts 類是不可變的,所有參數默認值都在一個位置。構建器的 setter 方法返回構建器本身,這樣就可以鏈式調用,從而得到一個流暢的 API。下面是客戶端代碼的樣子:
```
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
.calories(100).sodium(35).carbohydrate(27).build();
```
This client code is easy to write and, more importantly, easy to read. The Builder pattern simulates named optional parameters as found in Python and Scala.
該客戶端代碼易于編寫,更重要的是易于閱讀。建造者模式模擬 Python 和 Scala 中的可選參數。
Validity checks were omitted for brevity. To detect invalid parameters as soon as possible, check parameter validity in the builder’s constructor and methods.Check invariants involving multiple parameters in the constructor invoked by the build method. To ensure these invariants against attack, do the checks on object fields after copying parameters from the builder (Item 50). If a check fails, throw an IllegalArgumentException (Item 72) whose detail message indicates which parameters are invalid (Item 75).
為了簡潔,省略了有效性檢查。為了盡快檢測無效的參數,請檢查構建器的構造函數和方法中的參數有效性。檢查構建方法調用的構造函數中涉及多個參數的不變量。為了確保這些不變量不受攻擊,在從構建器復制參數之后檢查對象字段([Item-50](/Chapter-8/Chapter-8-Item-50-Make-defensive-copies-when-needed.md))。如果檢查失敗,拋出一個 IllegalArgumentException([Item-72](/Chapter-10/Chapter-10-Item-72-Favor-the-use-of-standard-exceptions.md)),它的詳細消息指示哪些參數無效([Item-75](/Chapter-10/Chapter-10-Item-75-Include-failure-capture-information-in-detail-messages.md))。
The Builder pattern is well suited to class hierarchies. Use a parallel hierarchy of builders, each nested in the corresponding class. Abstract classes have abstract builders; concrete classes have concrete builders. For example,consider an abstract class at the root of a hierarchy representing various kinds of pizza:
建造者模式非常適合于類層次結構。使用構建器的并行層次結構,每個構建器都嵌套在相應的類中。抽象類有抽象類構建器;具體類有具體類構建器。例如,考慮一個在層次結構處于最低端的抽象類,它代表各種比薩餅:
```
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
// Builder pattern for class hierarchies
public abstract class Pizza {
public enum Topping {HAM, MUSHROOM, ONION, PEPPER, SAUSAGE}
final Set<Topping> toppings;
abstract static class Builder<T extends Builder<T>> {
EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);
public T addTopping(Topping topping) {
toppings.add(Objects.requireNonNull(topping));
return self();
}
abstract Pizza build();
// Subclasses must override this method to return "this"
protected abstract T self();
}
Pizza(Builder<?> builder) {
toppings = builder.toppings.clone(); // See Item 50
}
}
```
Note that Pizza.Builder is a generic type with a recursive type parameter (Item 30). This, along with the abstract self method, allows method chaining to work properly in subclasses, without the need for casts. This workaround for the fact that Java lacks a self type is known as the simulated self-type idiom. Here are two concrete subclasses of Pizza, one of which represents a standard New-York-style pizza, the other a calzone. The former has a required size parameter, while the latter lets you specify whether sauce should be inside or out:
請注意,`Pizza.Builder` 是具有遞歸類型參數的泛型類型([Item-31](/Chapter-5/Chapter-5-Item-31-Use-bounded-wildcards-to-increase-API-flexibility.md))。這與抽象 self 方法一起,允許方法鏈接在子類中正常工作,而不需要強制轉換。對于 Java 缺少自類型這一事實,這種變通方法稱為模擬自類型習慣用法。這里有兩個具體的比薩子類,一個是標準的紐約風格的比薩,另一個是 calzone。前者有一個必需的尺寸大小參數,而后者讓你指定醬料應該放在里面還是外面:
```
import java.util.Objects;
public class NyPizza extends Pizza {
public enum Size {SMALL, MEDIUM, LARGE}
private final Size size;
public static class Builder extends Pizza.Builder<Builder> {
private final Size size;
public Builder(Size size) {
this.size = Objects.requireNonNull(size);
}
@Override
public NyPizza build() {
return new NyPizza(this);
}
@Override
protected Builder self() {
return this;
}
}
private NyPizza(Builder builder) {
super(builder);
size = builder.size;
}
}
public class Calzone extends Pizza {
private final boolean sauceInside;
public static class Builder extends Pizza.Builder<Builder> {
private boolean sauceInside = false; // Default
public Builder sauceInside() {
sauceInside = true;
return this;
}
@Override
public Calzone build() {
return new Calzone(this);
}
@Override
protected Builder self() {
return this;
}
}
private Calzone(Builder builder) {
super(builder);
sauceInside = builder.sauceInside;
}
}
```
Note that the build method in each subclass’s builder is declared to return the correct subclass: the build method of NyPizza.Builder returns NyPizza, while the one in Calzone.Builder returns Calzone. This technique, wherein a subclass method is declared to return a subtype of the return type declared in the super-class, is known as covariant return typing. It allows clients to use these builders without the need for casting.The client code for these “hierarchical builders” is essentially identical to the code for the simple NutritionFacts builder. The example client code shown next assumes static imports on enum constants for brevity:
注意,每個子類的構建器中的構建方法聲明為返回正確的子類:構建的方法 `NyPizza.Builder` 返回 NyPizza,而在 `Calzone.Builder` 則返回 Calzone。這種技術稱為協變返回類型,其中一個子類方法聲明為返回超類中聲明的返回類型的子類型。它允許客戶使用這些構建器,而不需要強制轉換。這些「層次構建器」的客戶端代碼與簡單的 NutritionFacts 構建器的代碼基本相同。為簡潔起見,下面顯示的示例客戶端代碼假定枚舉常量上的靜態導入:
```
NyPizza pizza = new NyPizza.Builder(SMALL)
.addTopping(SAUSAGE).addTopping(ONION).build();
Calzone calzone = new Calzone.Builder()
.addTopping(HAM).sauceInside().build();
```
A minor advantage of builders over constructors is that builders can have multiple varargs parameters because each parameter is specified in its own method. Alternatively, builders can aggregate the parameters passed into multiple calls to a method into a single field, as demonstrated in the addTopping method earlier.
與構造函數相比,構建器的一個小優點是構建器可以有多個變量參數,因為每個參數都是在自己的方法中指定的。或者,構建器可以將傳遞給一個方法的多個調用的參數聚合到單個字段中,如前面的 addTopping 方法中所示。
The Builder pattern is quite flexible. A single builder can be used repeatedly to build multiple objects. The parameters of the builder can be tweaked between invocations of the build method to vary the objects that are created. A builder can fill in some fields automatically upon object creation, such as a serial number that increases each time an object is created.
建造者模式非常靈活。一個構建器可以反復構建多個對象。構建器的參數可以在構建方法的調用之間進行調整,以改變創建的對象。構建器可以在創建對象時自動填充某些字段,例如在每次創建對象時增加的序列號。
The Builder pattern has disadvantages as well. In order to create an object,you must first create its builder. While the cost of creating this builder is unlikely to be noticeable in practice, it could be a problem in performance-critical situations. Also, the Builder pattern is more verbose than the telescoping constructor pattern, so it should be used only if there are enough parameters to make it worthwhile, say four or more. But keep in mind that you may want to add more parameters in the future. But if you start out with constructors or static factories and switch to a builder when the class evolves to the point where the number of parameters gets out of hand, the obsolete constructors or static factories will stick out like a sore thumb. Therefore, it’s often better to start with a builder in the first place.
建造者模式也有缺點。為了創建一個對象,你必須首先創建它的構建器。雖然在實際應用中創建這個構建器的成本可能并不顯著,但在以性能為關鍵的場景下,這可能會是一個問題。而且,建造者模式比可伸縮構造函數模式更冗長,因此只有在有足夠多的參數時才值得使用,比如有 4 個或更多參數時,才應該使用它。但是請記住,你可能希望在將來添加更多的參數。但是,如果你以構造函數或靜態工廠開始,直至類擴展到參數數量無法控制的程度時,也會切換到構建器,但是過時的構造函數或靜態工廠將很難處理。因此,最好一開始就從構建器開始。
In summary, the Builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters, especially if many of the parameters are optional or of identical type. Client code is much easier to read and write with builders than with telescoping constructors, and builders are much safer than JavaBeans.
總之,在設計構造函數或靜態工廠的類時,建造者模式是一個很好的選擇,特別是當許多參數是可選的或具有相同類型時。與可伸縮構造函數相比,使用構建器客戶端代碼更容易讀寫,而且構建器比 JavaBean 更安全。
### **隨筆**
每個內部 Builder 類要對每個字段建立相應方法,代碼比較冗長。若將「構建機制」獨立出來,或能廣泛適應相似結構的構建需求。以下是針對原文案例的簡要修改,僅供參考:
```
class EntityCreator<T> {
private Class<T> classInstance;
private T entityObj;
public EntityCreator(Class<T> classInstance, Object... initParams) throws Exception {
this.classInstance = classInstance;
Class<?>[] paramTypes = new Class<?>[initParams.length];
for (int index = 0, length = initParams.length; index < length; index++) {
String checkStr = initParams[index].getClass().getSimpleName();
if (checkStr.contains("Integer")) {
paramTypes[index] = int.class;
}
if (checkStr.contains("Double")) {
paramTypes[index] = double.class;
}
if (checkStr.contains("Boolean")) {
paramTypes[index] = boolean.class;
}
if (checkStr.contains("String")) {
paramTypes[index] = initParams[index].getClass();
}
}
Constructor<T> constructor = classInstance.getDeclaredConstructor(paramTypes);
constructor.setAccessible(true);
this.entityObj = constructor.newInstance(initParams);
}
public EntityCreator<T> setValue(String paramName, Object paramValue) throws Exception {
Field field = classInstance.getDeclaredField(paramName);
field.setAccessible(true);
field.set(entityObj, paramValue);
return this;
}
public T build() {
return entityObj;
}
}
```
如此,可移除整個內部 Builder 類,NutritionFacts 類私有構造的參數僅包括兩個必填的 servingSize、servings 字段:
```
public class NutritionFacts {
// 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;
private NutritionFacts(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
}
```
該案例的客戶端代碼改為:
```
NutritionFacts cocaCola = new EntityCreator<>(NutritionFacts.class, 240, 8)
.setValue("calories", 100)
.setValue("sodium", 35)
.setValue("carbohydrate", 27).build();
```
---
**[Back to contents of the chapter(返回章節目錄)](/Chapter-2/Chapter-2-Introduction.md)**
- **Previous Item(上一條目):[Item 1: Consider static factory methods instead of constructors(考慮以靜態工廠方法代替構造函數)](/Chapter-2/Chapter-2-Item-1-Consider-static-factory-methods-instead-of-constructors.md)**
- **Next Item(下一條目):[Item 3: Enforce the singleton property with a private constructor or an enum type(使用私有構造函數或枚舉類型實施單例屬性)](/Chapter-2/Chapter-2-Item-3-Enforce-the-singleton-property-with-a-private-constructor-or-an-enum-type.md)**
- Chapter 2. Creating and Destroying Objects(創建和銷毀對象)
- Item 1: Consider static factory methods instead of constructors(考慮以靜態工廠方法代替構造函數)
- Item 2: Consider a builder when faced with many constructor parameters(在面對多個構造函數參數時,請考慮構建器)
- Item 3: Enforce the singleton property with a private constructor or an enum type(使用私有構造函數或枚舉類型實施單例屬性)
- Item 4: Enforce noninstantiability with a private constructor(用私有構造函數實施不可實例化)
- Item 5: Prefer dependency injection to hardwiring resources(依賴注入優于硬連接資源)
- Item 6: Avoid creating unnecessary objects(避免創建不必要的對象)
- Item 7: Eliminate obsolete object references(排除過時的對象引用)
- Item 8: Avoid finalizers and cleaners(避免使用終結器和清除器)
- Item 9: Prefer try with resources to try finally(使用 try-with-resources 優于 try-finally)
- Chapter 3. Methods Common to All Objects(對象的通用方法)
- Item 10: Obey the general contract when overriding equals(覆蓋 equals 方法時應遵守的約定)
- Item 11: Always override hashCode when you override equals(當覆蓋 equals 方法時,總要覆蓋 hashCode 方法)
- Item 12: Always override toString(始終覆蓋 toString 方法)
- Item 13: Override clone judiciously(明智地覆蓋 clone 方法)
- Item 14: Consider implementing Comparable(考慮實現 Comparable 接口)
- Chapter 4. Classes and Interfaces(類和接口)
- Item 15: Minimize the accessibility of classes and members(盡量減少類和成員的可訪問性)
- Item 16: In public classes use accessor methods not public fields(在公共類中,使用訪問器方法,而不是公共字段)
- Item 17: Minimize mutability(減少可變性)
- Item 18: Favor composition over inheritance(優先選擇復合而不是繼承)
- Item 19: Design and document for inheritance or else prohibit it(繼承要設計良好并且具有文檔,否則禁止使用)
- Item 20: Prefer interfaces to abstract classes(接口優于抽象類)
- Item 21: Design interfaces for posterity(為后代設計接口)
- Item 22: Use interfaces only to define types(接口只用于定義類型)
- Item 23: Prefer class hierarchies to tagged classes(類層次結構優于帶標簽的類)
- Item 24: Favor static member classes over nonstatic(靜態成員類優于非靜態成員類)
- Item 25: Limit source files to a single top level class(源文件僅限有單個頂層類)
- Chapter 5. Generics(泛型)
- Item 26: Do not use raw types(不要使用原始類型)
- Item 27: Eliminate unchecked warnings(消除 unchecked 警告)
- Item 28: Prefer lists to arrays(list 優于數組)
- Item 29: Favor generic types(優先使用泛型)
- Item 30: Favor generic methods(優先使用泛型方法)
- Item 31: Use bounded wildcards to increase API flexibility(使用有界通配符增加 API 的靈活性)
- Item 32: Combine generics and varargs judiciously(明智地合用泛型和可變參數)
- Item 33: Consider typesafe heterogeneous containers(考慮類型安全的異構容器)
- Chapter 6. Enums and Annotations(枚舉和注解)
- Item 34: Use enums instead of int constants(用枚舉類型代替 int 常量)
- Item 35: Use instance fields instead of ordinals(使用實例字段替代序數)
- Item 36: Use EnumSet instead of bit fields(用 EnumSet 替代位字段)
- Item 37: Use EnumMap instead of ordinal indexing(使用 EnumMap 替換序數索引)
- Item 38: Emulate extensible enums with interfaces(使用接口模擬可擴展枚舉)
- Item 39: Prefer annotations to naming patterns(注解優于命名模式)
- Item 40: Consistently use the Override annotation(堅持使用 @Override 注解)
- Item 41: Use marker interfaces to define types(使用標記接口定義類型)
- Chapter 7. Lambdas and Streams(λ 表達式和流)
- Item 42: Prefer lambdas to anonymous classes(λ 表達式優于匿名類)
- Item 43: Prefer method references to lambdas(方法引用優于 λ 表達式)
- Item 44: Favor the use of standard functional interfaces(優先使用標準函數式接口)
- Item 45: Use streams judiciously(明智地使用流)
- Item 46: Prefer side effect free functions in streams(在流中使用無副作用的函數)
- Item 47: Prefer Collection to Stream as a return type(優先選擇 Collection 而不是流作為返回類型)
- Item 48: Use caution when making streams parallel(謹慎使用并行流)
- Chapter 8. Methods(方法)
- Item 49: Check parameters for validity(檢查參數的有效性)
- Item 50: Make defensive copies when needed(在需要時制作防御性副本)
- Item 51: Design method signatures carefully(仔細設計方法簽名)
- Item 52: Use overloading judiciously(明智地使用重載)
- Item 53: Use varargs judiciously(明智地使用可變參數)
- Item 54: Return empty collections or arrays, not nulls(返回空集合或數組,而不是 null)
- Item 55: Return optionals judiciously(明智地的返回 Optional)
- Item 56: Write doc comments for all exposed API elements(為所有公開的 API 元素編寫文檔注釋)
- Chapter 9. General Programming(通用程序設計)
- Item 57: Minimize the scope of local variables(將局部變量的作用域最小化)
- Item 58: Prefer for-each loops to traditional for loops(for-each 循環優于傳統的 for 循環)
- Item 59: Know and use the libraries(了解并使用庫)
- Item 60: Avoid float and double if exact answers are required(若需要精確答案就應避免使用 float 和 double 類型)
- Item 61: Prefer primitive types to boxed primitives(基本數據類型優于包裝類)
- Item 62: Avoid strings where other types are more appropriate(其他類型更合適時應避免使用字符串)
- Item 63: Beware the performance of string concatenation(當心字符串連接引起的性能問題)
- Item 64: Refer to objects by their interfaces(通過接口引用對象)
- Item 65: Prefer interfaces to reflection(接口優于反射)
- Item 66: Use native methods judiciously(明智地使用本地方法)
- Item 67: Optimize judiciously(明智地進行優化)
- Item 68: Adhere to generally accepted naming conventions(遵守被廣泛認可的命名約定)
- Chapter 10. Exceptions(異常)
- Item 69: Use exceptions only for exceptional conditions(僅在確有異常條件下使用異常)
- Item 70: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors(對可恢復情況使用 checked 異常,對編程錯誤使用運行時異常)
- Item 71: Avoid unnecessary use of checked exceptions(避免不必要地使用 checked 異常)
- Item 72: Favor the use of standard exceptions(鼓勵復用標準異常)
- Item 73: Throw exceptions appropriate to the abstraction(拋出能用抽象解釋的異常)
- Item 74: Document all exceptions thrown by each method(為每個方法記錄會拋出的所有異常)
- Item 75: Include failure capture information in detail messages(異常詳細消息中應包含捕獲失敗的信息)
- Item 76: Strive for failure atomicity(盡力保證故障原子性)
- Item 77: Don’t ignore exceptions(不要忽略異常)
- Chapter 11. Concurrency(并發)
- Item 78: Synchronize access to shared mutable data(對共享可變數據的同步訪問)
- Item 79: Avoid excessive synchronization(避免過度同步)
- Item 80: Prefer executors, tasks, and streams to threads(Executor、task、流優于直接使用線程)
- Item 81: Prefer concurrency utilities to wait and notify(并發實用工具優于 wait 和 notify)
- Item 82: Document thread safety(文檔應包含線程安全屬性)
- Item 83: Use lazy initialization judiciously(明智地使用延遲初始化)
- Item 84: Don’t depend on the thread scheduler(不要依賴線程調度器)
- Chapter 12. Serialization(序列化)
- Item 85: Prefer alternatives to Java serialization(優先選擇 Java 序列化的替代方案)
- Item 86: Implement Serializable with great caution(非常謹慎地實現 Serializable)
- Item 87: Consider using a custom serialized form(考慮使用自定義序列化形式)
- Item 88: Write readObject methods defensively(防御性地編寫 readObject 方法)
- Item 89: For instance control, prefer enum types to readResolve(對于實例控制,枚舉類型優于 readResolve)
- Item 90: Consider serialization proxies instead of serialized instances(考慮以序列化代理代替序列化實例)