## Chapter 3. Methods Common to All Objects(對象的通用方法)
### Item 12: Always override toString(始終覆蓋 toString 方法)
While Object provides an implementation of the toString method, the string that it returns is generally not what the user of your class wants to see. It consists of(由…組成) the class name followed by an “at” sign (@) and the unsigned hexadecimal representation of the hash code, for example,PhoneNumber@163b91. The general contract for toString says that the returned string should be “a concise but informative representation that is easy for a person to read.” While it could be argued that PhoneNumber@163b91 is concise and easy to read, it isn’t very informative when compared to 707-867-5309. The toString contract goes on to say, “It is recommended that all subclasses override this method.” Good advice, indeed!
雖然 Object 提供 toString 方法的實現,但它返回的字符串通常不是類的用戶希望看到的。它由后跟「at」符號(@)的類名和 hash 代碼的無符號十六進制表示(例如 PhoneNumber@163b91)組成。toString 的通用約定是這么描述的,返回的字符串應該是「簡潔但信息豐富的表示,易于閱讀」。雖然有人認為 PhoneNumber@163b91 簡潔易懂,但與 707-867-5309 相比,它的信息量并不大。toString 約定接著描述,「建議所有子類覆蓋此方法。」好建議,確實!
While it isn’t as critical as obeying the equals and hashCode contracts (Items 10 and 11), **providing a good toString implementation makes your class much more pleasant to use and makes systems using the class easier to debug.** The toString method is automatically invoked when an object is passed to println, printf, the string concatenation operator, or assert, or is printed by a debugger. Even if you never call toString on an object, others may. For example, a component that has a reference to your object may include the string representation of the object in a logged error message. If you fail to override toString, the message may be all but useless.
雖然它不如遵守 equals 和 hashCode 約定([Item-10](/Chapter-3/Chapter-3-Item-10-Obey-the-general-contract-when-overriding-equals.md) 和 [Item-11](/Chapter-3/Chapter-3-Item-11-Always-override-hashCode-when-you-override-equals.md))那么重要,但是 **提供一個好的 toString 實現(能)使類更易于使用,使用該類的系統(也)更易于調試。** 當對象被傳遞給 println、printf、字符串連接操作符或斷言或由調試器打印時,將自動調用 toString 方法。即使你從來沒有調用 toString 對象,其他人也可能(使用)。例如,有對象引用的組件可以在日志錯誤消息中包含對象的字符串表示。如果你未能覆蓋 toString,則該消息可能完全無用。
If you’ve provided a good toString method for PhoneNumber,generating a useful diagnostic message is as easy as this:
如果你已經為 PhoneNumber 提供了一個好的 toString 方法,那么生成一個有用的診斷消息就像這樣簡單:
```
System.out.println("Failed to connect to " + phoneNumber);
```
Programmers will generate diagnostic messages in this fashion whether or not you override toString, but the messages won’t be useful unless you do. The benefits of providing a good toString method extend beyond instances of the class to objects containing references to these instances, especially collections.Which would you rather see when printing a map,{Jenny=PhoneNumber@163b91} or {Jenny=707-867-5309}?
無論你是否覆蓋 toString,程序員都會以這種方式生成診斷消息,但是除非你(覆蓋 toString),否則這些消息不會有用。提供好的 toString 方法的好處不僅僅是將類的實例擴展到包含對這些實例的引用的對象,特別是集合。在打印 map 時,你更愿意看到哪個,{Jenny=PhoneNumber@163b91} 還是 {Jenny=707-867-5309}?
**When practical, the toString method should return all of the interesting information contained in the object,** as shown in the phone number example. It is impractical if the object is large or if it contains state that is not conducive to string representation. Under these circumstances,toString should return a summary such as Manhattan residential phone directory (1487536 listings) or Thread[main,5,main]. Ideally, the string should be self-explanatory. (The Thread example flunks this test.) A particularly annoying penalty for failing to include all of an object’s interesting information in its string representation is test failure reports that look like this:
**當實際使用時,toString 方法應該返回對象中包含的所有有趣信息,** 如電話號碼示例所示。如果對象很大,或者包含不利于字符串表示的狀態,那么這種方法是不切實際的。在這種情況下,toString 應該返回一個摘要,例如曼哈頓住宅電話目錄(1487536 號清單)或 Thread[main,5,main]。理想情況下,字符串應該是不言自明的。(線程示例未能通過此測試。)如果沒有在字符串表示中包含所有對象的有趣信息,那么一個特別惱人的懲罰就是測試失敗報告,如下所示:
```
Assertion failure: expected {abc, 123}, but was {abc, 123}.
```
One important decision you’ll have to make when implementing a toString method is whether to specify the format of the return value in the documentation. It is recommended that you do this for value classes, such as phone number or matrix. The advantage of specifying the format is that it serves as a standard, unambiguous, human-readable representation of the object. This representation can be used for input and output and in persistent human-readable data objects, such as CSV files. If you specify the format, it’s usually a good idea to provide a matching static factory or constructor so programmers can easily translate back and forth between the object and its string representation. This approach is taken by many value classes in the Java platform libraries, including BigInteger, BigDecimal, and most of the boxed primitive classes.
在實現 toString 方法時,你必須做的一個重要決定是是否在文檔中指定返回值的格式。建議你針對值類(如電話號碼或矩陣)這樣做。指定格式的優點是,它可以作為對象的標準的、明確的、人類可讀的表示。這種表示可以用于輸入和輸出,也可以用于持久的人類可讀數據對象,比如 CSV 文件。如果指定了格式,提供一個匹配的靜態工廠或構造函數通常是一個好主意,這樣程序員就可以輕松地在對象及其字符串表示之間來回轉換。Java 庫中的許多值類都采用這種方法,包括 BigInteger、BigDecimal 和大多數包裝類。
The disadvantage of specifying the format of the toString return value is that once you’ve specified it, you’re stuck with it for life, assuming your class is widely used. Programmers will write code to parse the representation, to generate it, and to embed it into persistent data. If you change the representation in a future release, you’ll break their code and data, and they will yowl. By choosing not to specify a format, you preserve the flexibility to add information or improve the format in a subsequent release.
指定 toString 返回值的格式的缺點是,一旦指定了它,就會終生使用它,假設你的類被廣泛使用。程序員將編寫代碼來解析表示、生成表示并將其嵌入持久數據中。如果你在將來的版本中更改了表示形式,你將破壞它們的代碼和數據,它們將發出大量的消息。通過選擇不指定格式,你可以保留在后續版本中添加信息或改進格式的靈活性。
**Whether or not you decide to specify the format, you should clearly document your intentions.** If you specify the format, you should do so precisely. For example, here’s a toString method to go with the PhoneNumber class in Item 11:
**無論你是否決定指定格式,你都應該清楚地記錄你的意圖。** 如果指定了格式,則應該精確地指定格式。例如,這里有一個 toString 方法用于[Item-11](/Chapter-3/Chapter-3-Item-11-Always-override-hashCode-when-you-override-equals.md)中的 PhoneNumber 類:
```
/**
* Returns the string representation of this phone number.
* The string consists of twelve characters whose format is
* "XXX-YYY-ZZZZ", where XXX is the area code, YYY is the
* prefix, and ZZZZ is the line number. Each of the capital
* letters represents a single decimal digit.
**
If any of the three parts of this phone number is too small
* to fill up its field, the field is padded with leading zeros.
* For example, if the value of the line number is 123, the last
* four characters of the string representation will be "0123".
*/
@Override
public String toString() {
return String.format("%03d-%03d-%04d", areaCode, prefix, lineNum);
}
```
If you decide not to specify a format, the documentation comment should read something like this:
如果你決定不指定一種格式,文檔注釋應該如下所示:
```
/**
* Returns a brief description of this potion. The exact details
* of the representation are unspecified and subject to change,
* but the following may be regarded as typical:
**
"[Potion #9: type=love, smell=turpentine, look=india ink]"
*/
@Override
public String toString() { ... }
```
After reading this comment, programmers who produce code or persistent data that depends on the details of the format will have no one but themselves to blame when the format is changed.
在閱讀了這篇文檔注釋之后,當格式被更改時,生成依賴于格式細節的代碼或持久數據的程序員將只能怪他們自己。
Whether or not you specify the format, **provide programmatic access to the information contained in the value returned by toString.** For example, the PhoneNumber class should contain accessors for the area code, prefix, and line number. If you fail to do this, you force programmers who need this information to parse the string. Besides reducing performance and making unnecessary work for programmers, this process is error-prone and results in fragile systems that break if you change the format. By failing to provide accessors, you turn the string format into a de facto API, even if you’ve specified that it’s subject to change.
無論你是否指定了格式,都要 **提供對 toString 返回值中包含的信息的程序性訪問。** 例如,PhoneNumber 類應該包含區域代碼、前綴和行號的訪問器。如果做不到這一點,就會迫使需要這些信息的程序員解析字符串。除了降低性能和使程序員不必要的工作之外,這個過程很容易出錯,并且會導致脆弱的系統在你更改格式時崩潰。由于沒有提供訪問器,你可以將字符串格式轉換為事實上的 API,即使你已經指定了它可能會發生更改。
It makes no sense to write a toString method in a static utility class (Item 4). Nor should you write a toString method in most enum types (Item 34) because Java provides a perfectly good one for you. You should, however, write a toString method in any abstract class whose subclasses share a common string representation. For example, the toString methods on most collection implementations are inherited from the abstract collection classes.
在靜態實用程序類中編寫 toString 方法是沒有意義的([Item-4](/Chapter-2/Chapter-2-Item-4-Enforce-noninstantiability-with-a-private-constructor.md)),在大多數 enum 類型中也不應該編寫 toString 方法([Item-34](/Chapter-6/Chapter-6-Item-34-Use-enums-instead-of-int-constants.md)),因為 Java 為你提供了一個非常好的方法。但是,你應該在任何抽象類中編寫 toString 方法,該類的子類共享公共的字符串表示形式。例如,大多數集合實現上的 toString 方法都繼承自抽象集合類。
Google’s open source AutoValue facility, discussed in Item 10, will generate a toString method for you, as will most IDEs. These methods are great for telling you the contents of each field but aren’t specialized to the meaning of the class. So, for example, it would be inappropriate to use an automatically generated toString method for our PhoneNumber class (as phone numbers have a standard string representation), but it would be perfectly acceptable for our Potion class. That said, an automatically generated toString method is far preferable to the one inherited from Object, which tells you nothing about an object’s value.
谷歌的開放源碼自動值工具(在 [Item-10](/Chapter-3/Chapter-3-Item-10-Obey-the-general-contract-when-overriding-equals.md) 中討論)將為你生成 toString 方法,大多數 IDE 也是如此。這些方法可以很好地告訴你每個字段的內容,但并不專門針對類的含義。因此,例如,對于 PhoneNumber 類使用自動生成的 toString 方法是不合適的(因為電話號碼具有標準的字符串表示形式),但是對于 Potion 類來說它是完全可以接受的。也就是說,一個自動生成的 toString 方法要比從對象繼承的方法好得多,對象繼承的方法不會告訴你對象的值。
To recap, override Object’s toString implementation in every instantiable class you write, unless a superclass has already done so. It makes classes much more pleasant to use and aids in debugging. The toString method should return a concise, useful description of the object, in an aesthetically pleasing format.
回顧一下,在你編寫的每個實例化類中覆蓋對象的 toString 實現,除非超類已經這樣做了。它使類更易于使用,并有助于調試。toString 方法應該以美觀的格式返回對象的簡明、有用的描述。
---
**[Back to contents of the chapter(返回章節目錄)](/Chapter-3/Chapter-3-Introduction.md)**
- **Previous Item(上一條目):[Item 11: Always override hashCode when you override equals(當覆蓋 equals 方法時,總要覆蓋 hashCode 方法)](/Chapter-3/Chapter-3-Item-11-Always-override-hashCode-when-you-override-equals.md)**
- **Next Item(下一條目):[Item 13: Override clone judiciously(明智地覆蓋 clone 方法)](/Chapter-3/Chapter-3-Item-13-Override-clone-judiciously.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(考慮以序列化代理代替序列化實例)