## Chapter 2. Creating and Destroying Objects(創建和銷毀對象)
### Item 8: Avoid finalizers and cleaners(避免使用終結器和清除器)
**Finalizers are unpredictable, often dangerous, and generally unnecessary.** Their use can cause erratic behavior, poor performance, and portability problems. Finalizers have a few valid uses, which we’ll cover later in this item, but as a rule, you should avoid them. As of Java 9, finalizers have been deprecated, but they are still being used by the Java libraries. The Java 9 replacement for finalizers is cleaners. **Cleaners are less dangerous than finalizers, but still unpredictable, slow, and generally unnecessary.**
**終結器是不可預測的,通常是危險的,也是不必要的。** 它們的使用可能導致不穩定的行為、糟糕的性能和可移植性問題。終結器有一些有效的用途,我們將在后面的文章中介紹,但是作為規則,你應該避免使用它們。在 Java 9 中,終結器已經被棄用,但是 Java 庫仍然在使用它們。Java 9 替代終結器的是清除器。**清除器的危險比終結器小,但仍然不可預測、緩慢,而且通常是不必要的。**
C++ programmers are cautioned not to think of finalizers or cleaners as Java’s analogue of C++ destructors. In C++, destructors are the normal way to reclaim the resources associated with an object, a necessary counterpart to constructors.In Java, the garbage collector reclaims the storage associated with an object when it becomes unreachable, requiring no special effort on the part of the programmer. C++ destructors are also used to reclaim other nonmemory resources. In Java, a try-with-resources or try-finally block is used for this purpose (Item 9).
c++ 程序員被告誡不要把終結器或清除器當成 Java 的 c++ 析構函數。在 c++ 中,析構函數是回收與對象相關聯的資源的常用方法,對象是構造函數的必要對等物。在 Java 中,當對象變得不可訪問時,垃圾收集器將回收與之關聯的存儲,無需程序員進行任何特殊工作。c++ 析構函數還用于回收其他非內存資源。在 Java 中,使用帶有資源的 try-with-resources 或 try-finally 塊用于此目的([Item-9](/Chapter-2/Chapter-2-Item-9-Prefer-try-with-resources-to-try-finally.md))。
One shortcoming of finalizers and cleaners is that there is no guarantee they’ll be executed promptly [JLS, 12.6]. It can take arbitrarily long between the time that an object becomes unreachable and the time its finalizer or cleaner runs.This means that you should never do anything time-critical in a finalizer or cleaner. For example, it is a grave error to depend on a finalizer or cleaner to close files because open file descriptors are a limited resource. If many files are left open as a result of the system’s tardiness in running finalizers or cleaners, a program may fail because it can no longer open files.
終結器和清除器的一個缺點是不能保證它們會被立即執行 [JLS, 12.6]。當對象變得不可訪問,終結器或清除器對它進行操作的時間是不確定的。這意味著永遠不應該在終結器或清除器中執行任何對時間要求很嚴格的操作。例如,依賴終結器或清除器關閉文件就是一個嚴重錯誤,因為打開的文件描述符是有限的資源。如果由于系統在運行終結器或清除器的延遲導致許多文件處于打開狀態,程序可能會運行失敗,因為它不能再打開其他文件。
The promptness with which finalizers and cleaners are executed is primarily a function of the garbage collection algorithm, which varies widely across implementations. The behavior of a program that depends on the promptness of finalizer or cleaner execution may likewise vary. It is entirely possible that such a program will run perfectly on the JVM on which you test it and then fail miserably on the one favored by your most important customer.
終結器和清除器執行的快速性主要是垃圾收集算法的功能,在不同的實現中存在很大差異。依賴于終結器的及時性或更清晰的執行的程序的行為可能也會發生變化。這樣的程序完全有可能在測試它的 JVM 上完美地運行,然后在最重要的客戶喜歡的 JVM 上悲慘地失敗。
Tardy finalization is not just a theoretical problem. Providing a finalizer for a class can arbitrarily delay reclamation of its instances. A colleague debugged a long-running GUI application that was mysteriously dying with an OutOfMemoryError. Analysis revealed that at the time of its death, the application had thousands of graphics objects on its finalizer queue just waiting to be finalized and reclaimed. Unfortunately, the finalizer thread was running at a lower priority than another application thread, so objects weren’t getting finalized at the rate they became eligible for finalization. The language specification makes no guarantees as to which thread will execute finalizers, so there is no portable way to prevent this sort of problem other than to refrain from using finalizers. Cleaners are a bit better than finalizers in this regard because class authors have control over their own cleaner threads, but cleaners still run in the background, under the control of the garbage collector, so there can be no guarantee of prompt cleaning.
姍姍來遲的定稿不僅僅是一個理論上的問題。為類提供終結器可以任意延遲其實例的回收。一位同事調試了一個長期運行的 GUI 應用程序,該應用程序神秘地終結于 OutOfMemoryError 錯誤。分析顯示,在應用程序終結的時候,終結器隊列上有數千個圖形對象等待最終完成和回收。不幸的是,終結器線程運行的優先級低于另一個應用程序線程,因此對象不能以適合終結器的速度完成。語言規范沒有保證哪個線程將執行終結器,因此除了避免使用終結器之外,沒有其他可移植的方法來防止這類問題。在這方面,清潔器比終結器要好一些,因為類作者可以自己控制是否清理線程,但是清潔器仍然在后臺運行,在垃圾收集器的控制下運行,所以不能保證及時清理。
Not only does the specification provide no guarantee that finalizers or cleaners will run promptly; it provides no guarantee that they’ll run at all. It is entirely possible, even likely, that a program terminates without running them on some objects that are no longer reachable. As a consequence, you should never depend on a finalizer or cleaner to update persistent state. For example,depending on a finalizer or cleaner to release a persistent lock on a shared resource such as a database is a good way to bring your entire distributed system to a grinding halt.
該規范不僅不能保證終結器或清潔劑能及時運行;它并不能保證它們能運行。完全有可能,甚至很有可能,程序在某些不再可訪問的對象上運行而終止。因此,永遠不應該依賴終結器或清除器來更新持久狀態。例如,依賴終結器或清除器來釋放共享資源(如數據庫)上的持久鎖,是讓整個分布式系統停止工作的好方法。
Don’t be seduced by the methods System.gc and System.runFinalization. They may increase the odds of finalizers or cleaners getting executed, but they don’t guarantee it. Two methods once claimed to make this guarantee: System.runFinalizersOnExit and its evil twin, Runtime.runFinalizersOnExit. These methods are fatally flawed and have been deprecated for decades [ThreadStop].
不要被 System.gc 和 System.runFinalization 的方法所誘惑。它們可能會增加終結器或清除器被運行的幾率,但它們不能保證一定運行。曾經有兩種方法聲稱可以保證這一點:System.runFinalizersOnExit 和它的孿生兄弟 Runtime.runFinalizersOnExit。這些方法存在致命的缺陷,并且已經被廢棄了幾十年[ThreadStop]。
Another problem with finalizers is that an uncaught exception thrown during finalization is ignored, and finalization of that object terminates [JLS, 12.6].Uncaught exceptions can leave other objects in a corrupt state. If another thread attempts to use such a corrupted object, arbitrary nondeterministic behavior may result. Normally, an uncaught exception will terminate the thread and print a stack trace, but not if it occurs in a finalizer—it won’t even print a warning.Cleaners do not have this problem because a library using a cleaner has control over its thread.
終結器的另一個問題是,在終結期間拋出的未捕獲異常被忽略,該對象的終結終止 [JLS, 12.6]。未捕獲的異常可能會使其他對象處于損壞狀態。如果另一個線程試圖使用這樣一個損壞的對象,可能會導致任意的不確定性行為。正常情況下,未捕獲的異常將終止線程并打印堆棧跟蹤,但如果在終結器中出現,則不會打印警告。清除器沒有這個問題,因為使用清除器的庫可以控制它的線程。
There is a severe performance penalty for using finalizers and cleaners.On my machine, the time to create a simple AutoCloseable object, to close it using try-with-resources, and to have the garbage collector reclaim it is about 12 ns. Using a finalizer instead increases the time to 550 ns. In other words, it is about 50 times slower to create and destroy objects with finalizers. This is primarily because finalizers inhibit efficient garbage collection. Cleaners are comparable in speed to finalizers if you use them to clean all instances of the class (about 500 ns per instance on my machine), but cleaners are much faster if you use them only as a safety net, as discussed below. Under these circumstances, creating, cleaning, and destroying an object takes about 66 ns on my machine, which means you pay a factor of five (not fifty) for the insurance of a safety net if you don’t use it.
使用終結器和清除器會嚴重影響性能。在我的機器上,創建一個簡單的 AutoCloseable 對象,使用 try-with-resources 關閉它以及讓垃圾收集器回收它的時間大約是 12ns。相反,使用終結器將時間增加到 550ns。換句話說,使用終結器創建和銷毀對象大約要慢 50 倍。這主要是因為終結器抑制了有效的垃圾收集。如果使用清除器清除的所有實例(在我的機器上每個實例大約 500ns),那么清除器的速度與終結器相當,但是如果只將它們作為安全網來使用,清除器的速度要快得多,如下所述。在這種情況下,在我的機器上創建、清理和銷毀一個對象需要花費 66ns 的時間,這意味著如果你不使用它,你需要多出五倍(而不是五十倍)的保障成本。
Finalizers have a serious security problem: they open your class up to finalizer attacks. The idea behind a finalizer attack is simple: If an exception is thrown from a constructor or its serialization equivalents—the readObject and readResolve methods (Chapter 12)—the finalizer of a malicious subclass can run on the partially constructed object that should have “died on the vine.” This finalizer can record a reference to the object in a static field,preventing it from being garbage collected. Once the malformed object has been recorded, it is a simple matter to invoke arbitrary methods on this object that should never have been allowed to exist in the first place. Throwing an exception from a constructor should be sufficient to prevent an object from coming into existence; in the presence of finalizers, it is not. Such attacks can have dire consequences. Final classes are immune to finalizer attacks because no one can write a malicious subclass of a final class. To protect nonfinal classes from finalizer attacks, write a final finalize method that does nothing.
終結器有一個嚴重的安全問題:它們會讓你的類受到終結器攻擊。終結器攻擊背后的思想很簡單:如果從構造函數或它的序列化等價物(readObject 和 readResolve 方法([Item-12](/Chapter-3/Chapter-3-Item-12-Always-override-toString.md)))拋出一個異常,惡意子類的終結器就可以運行在部分構造的對象上,而這個對象本來應該「胎死腹中」。這個終結器可以在靜態字段中記錄對對象的引用,防止它被垃圾收集。一旦記錄了畸形對象,就很容易在這個對象上調用本來就不應該存在的任意方法。從構造函數拋出異常應該足以防止對象的出現;在有終結器的情況下,就不是這樣了。這樣的攻擊可能會造成可怕的后果。最終類對終結器攻擊免疫,因為沒有人能夠編寫最終類的惡意子類。為了保護非最終類不受終結器攻擊,編寫一個不執行任何操作的最終終結方法。
So what should you do instead of writing a finalizer or cleaner for a class whose objects encapsulate resources that require termination, such as files or threads? Just have your class implement AutoCloseable, and require its clients to invoke the close method on each instance when it is no longer needed, typically using try-with-resources to ensure termination even in the face of exceptions (Item 9). One detail worth mentioning is that the instance must keep track of whether it has been closed: the close method must record in a field that the object is no longer valid, and other methods must check this field and throw an IllegalStateException if they are called after the object has been closed.
那么,如果一個類的對象封裝了需要終止的資源,例如文件或線程,那么應該做什么,而不是為它編寫終結器或清除器呢?只有你的類實現 AutoCloseable,要求其客戶端每個實例在不再需要時調用關閉方法,通常使用 try-with-resources 確保終止,即使面對異常([Item-9](/Chapter-2/Chapter-2-Item-9-Prefer-try-with-resources-to-try-finally.md))。一個值得一提的細節是實例必須跟蹤是否已經關閉:close 方法必須在字段中記錄對象不再有效,其他方法必須檢查這個字段,如果在對象關閉后調用它們,則必須拋出一個 IllegalStateException。
So what, if anything, are cleaners and finalizers good for? They have perhaps two legitimate uses. One is to act as a safety net in case the owner of a resource neglects to call its close method. While there’s no guarantee that the cleaner or finalizer will run promptly (or at all), it is better to free the resource late than never if the client fails to do so. If you’re considering writing such a safety-net finalizer, think long and hard about whether the protection is worth the cost.Some Java library classes, such as FileInputStream,FileOutputStream, ThreadPoolExecutor, and java.sql.Connection, have finalizers that serve as safety nets.
那么,清除器和終結器有什么用呢?它們可能有兩種合法用途。一種是充當一個安全網,以防資源的所有者忽略調用它的 close 方法。雖然不能保證清除器或終結器將立即運行(或根本不運行),但如果客戶端沒有這樣做,最好是延遲釋放資源。如果你正在考慮編寫這樣一個安全網絡終結器,那就好好考慮一下這種保護是否值得。一些 Java 庫類,如 FileInputStream、FileOutputStream、ThreadPoolExecutor 和 java.sql.Connection,都有終結器作為安全網。
A second legitimate use of cleaners concerns objects with native peers. A native peer is a native (non-Java) object to which a normal object delegates via native methods. Because a native peer is not a normal object, the garbage collector doesn’t know about it and can’t reclaim it when its Java peer is reclaimed. A cleaner or finalizer may be an appropriate vehicle for this task,assuming the performance is acceptable and the native peer holds no critical resources. If the performance is unacceptable or the native peer holds resources that must be reclaimed promptly, the class should have a close method, as described earlier.
清潔器的第二個合法使用涉及到與本機對等體的對象。本機對等點是普通對象通過本機方法委托給的本機(非 java)對象。因為本機對等點不是一個正常的對象,垃圾收集器不知道它,并且不能在回收 Java 對等點時回收它。如果性能是可接受的,并且本機對等體不持有任何關鍵資源,那么更清潔或終結器可能是完成這項任務的合適工具。如果性能不可接受,或者本機對等體持有必須立即回收的資源,則類應該具有前面描述的關閉方法。
Cleaners are a bit tricky to use. Below is a simple Room class demonstrating the facility. Let’s assume that rooms must be cleaned before they are reclaimed.The Room class implements AutoCloseable; the fact that its automatic cleaning safety net uses a cleaner is merely an implementation detail. Unlike finalizers, cleaners do not pollute a class’s public API:
清除器的使用有些棘手。下面是一個簡單的 Room 類,展示了這個設施。讓我們假設房間在回收之前必須被清理。Room 類實現了 AutoCloseable;它的自動清洗安全網使用了清除器,這只是一個實現細節。與終結器不同,清除器不會污染類的公共 API:
```
import sun.misc.Cleaner;
// An autocloseable class using a cleaner as a safety net
public class Room implements AutoCloseable {
private static final Cleaner cleaner = Cleaner.create();
// Resource that requires cleaning. Must not refer to Room!
private static class State implements Runnable {
int numJunkPiles; // Number of junk piles in this room
State(int numJunkPiles) {
this.numJunkPiles = numJunkPiles;
}
// Invoked by close method or cleaner
@Override
public void run() {
System.out.println("Cleaning room");
numJunkPiles = 0;
}
}
// The state of this room, shared with our cleanable
private final State state;
// Our cleanable. Cleans the room when it’s eligible for gc
private final Cleaner.Cleanable cleanable;
public Room(int numJunkPiles) {
state = new State(numJunkPiles);
cleanable = cleaner.register(this, state);
}
@Override
public void close() {
cleanable.clean();
}
}
```
The static nested State class holds the resources that are required by the cleaner to clean the room. In this case, it is simply the numJunkPiles field,which represents the amount of mess in the room. More realistically, it might be a final long that contains a pointer to a native peer. State implements Runnable, and its run method is called at most once, by the Cleanable that we get when we register our State instance with our cleaner in the Room constructor. The call to the run method will be triggered by one of two things:Usually it is triggered by a call to Room’s close method calling Cleanable’s clean method. If the client fails to call the close method by the time a Room instance is eligible for garbage collection, the cleaner will (hopefully) call State’s run method.
靜態嵌套 State 類持有清潔器清潔房間所需的資源。在這種情況下,它僅僅是 numJunkPiles 字段,表示房間的混亂程度。更實際地說,它可能是最后一個包含指向本機對等點的 long 指針。State 實現了 Runnable,它的運行方法最多被調用一次,由我們在 Room 構造器中向 cleaner 實例注冊狀態實例時得到的 Cleanable 調用。對 run 方法的調用將由以下兩種方法之一觸發:通常是通過調用 Room 的 close 方法來觸發,調用 Cleanable 的 clean 方法。如果當一個 Room 實例有資格進行垃圾收集時,客戶端沒有調用 close 方法,那么清除器將調用 State 的 run 方法(希望如此)。
It is critical that a State instance does not refer to its Room instance. If it did, it would create a circularity that would prevent the Room instance from becoming eligible for garbage collection (and from being automatically cleaned).Therefore, State must be a static nested class because nonstatic nested classes contain references to their enclosing instances (Item 24). It is similarly inadvisable to use a lambda because they can easily capture references to enclosing objects.
狀態實例不引用其 Room 實例是非常重要的。如果它這樣做了,它將創建一個循環,以防止 Room 實例有資格進行垃圾收集(以及自動清理)。因此,狀態必須是一個靜態嵌套類,因為非靜態嵌套類包含對其封閉實例的引用([Item-24](/Chapter-4/Chapter-4-Item-24-Favor-static-member-classes-over-nonstatic.md))。同樣不建議使用 lambda,因為它們可以很容易地捕獲對包圍對象的引用。
As we said earlier, Room’s cleaner is used only as a safety net. If clients surround all Room instantiations in try-with-resource blocks, automatic cleaning will never be required. This well-behaved client demonstrates that behavior:
就像我們之前說的,Room 類的清除器只是用作安全網。如果客戶端將所有 Room 實例包圍在帶有資源的 try 塊中,則永遠不需要自動清理。這位表現良好的客戶端展示了這種做法:
```
public class Adult {
public static void main(String[] args) {
try (Room myRoom = new Room(7)) {
System.out.println("Goodbye");
}
}
}
```
As you’d expect, running the Adult program prints Goodbye, followed by Cleaning room. But what about this ill-behaved program, which never cleans its room?
如你所料,運行 Adult 程序打印「Goodbye」,然后是打掃房間。但這個從不打掃房間的不守規矩的程序怎么辦?
```
public class Teenager {
public static void main(String[] args) {
new Room(99);
System.out.println("Peace out");
}
}
```
You might expect it to print Peace out, followed by Cleaning room, but on my machine, it never prints Cleaning room; it just exits. This is the unpredictability we spoke of earlier. The Cleaner spec says, “The behavior of cleaners during System.exit is implementation specific. No guarantees are made relating to whether cleaning actions are invoked or not.” While the spec does not say it, the same holds true for normal program exit. On my machine,adding the line System.gc() to Teenager’s main method is enough to make it print Cleaning room prior to exit, but there’s no guarantee that you’ll see the same behavior on your machine.In summary, don’t use cleaners, or in releases prior to Java 9, finalizers,except as a safety net or to terminate noncritical native resources. Even then,beware the indeterminacy and performance consequences.
你可能期望它打印出「Peace out」,然后打掃房間,但在我的機器上,它從不打掃房間;它只是退出。這就是我們之前提到的不可預測性。Cleaner 規范說:「在 System.exit 中,清潔器的行為是特定于實現的。不保證清理操作是否被調用。」雖然規范沒有說明,但對于普通程序退出來說也是一樣。在我的機器上,將 System.gc() 添加到 Teenager 的主要方法中就足以讓它在退出之前打掃房間,但不能保證在其他機器上看到相同的行為。總之,不要使用清潔器,或者在 Java 9 之前的版本中使用終結器,除非是作為安全網或終止非關鍵的本機資源。即便如此,也要小心不確定性和性能后果。
---
**[Back to contents of the chapter(返回章節目錄)](/Chapter-2/Chapter-2-Introduction.md)**
- **Previous Item(上一條目):[Item 7: Eliminate obsolete object references(排除過時的對象引用)](/Chapter-2/Chapter-2-Item-7-Eliminate-obsolete-object-references.md)**
- **Next Item(下一條目):[Item 9: Prefer try with resources to try finally(使用 try-with-resources 優于 try-finally)](/Chapter-2/Chapter-2-Item-9-Prefer-try-with-resources-to-try-finally.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(考慮以序列化代理代替序列化實例)