Effective Java 2.0_中英文對照_Item 10

文章作者:Tyan
博客:noahsnail.com | CSDN | 簡書

Item10: Always override toString

While java.lang.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” [JavaSE6]. 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!

盡管java.lang.Object提供了toString方法的實現(xiàn),但是通常情況下它返回的字符串不是使用類的用戶想要的。返回的字符串包含類名,后面是一個@符號加上哈希碼的十六進制表示,例如PhoneNumber@163b91toString的通用約定指出,返回值應該是“簡潔但易讀的信息表示”[JavaSE6]。雖然可以認為PhoneNumber@163b91簡潔易讀,但它與(707) 867-5309相比,它的信息不夠豐富。toString約定進一步指出,“建議所有的子類重寫這個方法”。確實是個好建議。

While it isn’t as important as obeying the equals and hashCode contracts (Item 8, Item 9), providing a good toString implementation makes your class much more pleasant to use. The toString method is automatically invoked when an object is passed to println, printf, the string concatenation operator, or assert, or printed by a debugger. (The printf method was added to the platform in release 1.5, as were related methods including String.format, which is roughly equivalent to C’s sprintf.)

雖然它不像遵守equalshashCode約定(Item 8, Item 9)那樣重要,但是提供一個好的toString實現(xiàn)可以使你的類用起來更舒適。當對象傳到printlnprintf,字符串連接操作符,或assert中,或通過調試器打印時,會自動調用toString方法。(Java 1.5版本中平臺加入了printf方法,相關的方法包括String.format,類似于C語言中的sprintf方法)。

If you’ve provided a good toString method for PhoneNumber, generating a useful diagnostic message is as easy as this:

如果你已經(jīng)為PhoneNumber提供了一個好的toString方法,生成有用的診斷信息是很容易的:

System.out.println("Failed to connect: " + 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方法的好處是除了類的實例之外,也擴展了包含這些實例引用的對象,尤其是集合。當打印一個映射時,{Jenny=PhoneNumber@163b91}{Jenny=(707) 867-5309}你更喜歡哪一個?

When practical, the toString method should return all of the interesting information contained in the object, as in the phone number example just shown. 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 white pages (1487536 listings)” or “Thread[main,5,main]”. Ideally, the string should be self-explanatory. (The Thread example flunks this test.)

當實踐時,toString方法應該返回包含在對象中的所有的感興趣信息,正如剛才電話號碼的例子展示的那樣。如果對象很大或它包含不能用字符串表示的狀態(tài),重寫toString方法是不切實際的。在這種情況下,toString應該返回一個概要信息,例如Manhattan white pages (1487536 listings)Thread[main,5,main]。理想情況下,字符串應該是自解釋的。(Thread例子不能滿足這樣的要求。)

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 numbers or matrices. 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 XML documents. 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.

當實現(xiàn)toString時,你要做的一個重要決定是是否在文檔中指定返回值的格式。對于值類建議你這樣做,例如電話號碼或矩陣。指定返回值格式的優(yōu)勢在于它能為對象提供一個標準的,清晰的,可讀的表示。這個表示可以用在輸入輸出中,也可以用在一致的可讀數(shù)據(jù)對象中,例如XML文檔。如果你指定了格式,提供一個匹配的靜態(tài)工廠或構造函數(shù)通常是一個好主意,程序員可以很容易地在對象和它的字符串表示之間來回轉換。Java平臺庫中許多值類都采用了這個方法,包括BigIntegerBigDecimal和大多數(shù)基本類型的包裝類。

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 failing to specify a format, you preserve the flexibility to add information or improve the format in a subsequent release.

指定toString返回值格式的劣勢在于一旦你指定了它,假設你的類被廣泛使用,你就必須一直堅持它。程序員將會寫代碼轉換這種表示,產(chǎn)生這種格式并將它嵌入到持久化數(shù)據(jù)中。如果你在將來的版本中更改了表示格式,你將會破壞他們的代碼和數(shù)據(jù),他們將會抱怨。如果你沒有指定格式,你保留了添加信息的靈活性或者在后續(xù)版本改進這種格式。

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 9:

無論你決定是否指定格式,你都應該清楚地表明你的意圖。如果你指定了格式,你應該準確的去做。例如,下面的Item 9中PhoneNumber類的toString方法:

 /**
    * Returns the string representation of this phone number.
    * The string consists of fourteen 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". *
    * Note that there is a single space separating the closing
    s* parenthesis after the area code from the first digit of the * prefix.
*/
@Override public String toString() {
       return String.format("(%03d) %03d-%04d",areaCode, prefix, lineNumber);
}

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.

寫代碼或持久化數(shù)據(jù)的依賴于格式細節(jié)的程序員,在讀了這個文檔之后,一旦格式改變,只能自己負責后果。

Whether or not you specify the format,** provide programmatic access to all of 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類應該包含區(qū)域碼,前綴和行號的訪問器。如果你沒有這樣做,你會迫使需要這個信息的程序員取轉換這個字符串。除了為程序員降低效率和造成不必要的工作之外,這個過程中很容易出錯,而且會導致系統(tǒng)非常脆弱,如果你更改了格式系統(tǒng)會崩潰。如果沒有提供訪問器,即使你指明了字符串格式是可以變化的,這個字符串格式也變成了實際上的API。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容