1. 程式人生 > 其它 >時時重寫toString-第三章通用的方法-Effective Java學習筆記11

時時重寫toString-第三章通用的方法-Effective Java學習筆記11

技術標籤:java

學習筆記@Effective Java

文章內容來源於Joshua Bloch - Effective Java (3rd) - 2018.chm一書

第三章

通用的方法

Item 12總是重寫toString

雖然Object 提供了toString方法的實現,但它返回的字串通常不是類使用者希望看到的。
它由類名後接@符號和無標識的十六進位制雜湊程式碼組成表示,例如,[email protected]
toString的規約規定,返回的字串應該是“一種簡潔但資訊豐富的表示。但是[email protected]

是否簡潔易讀是有爭議的,相比於707-867-5309。
toString規約接著寫道,“建議所有子類重寫這個方法。”
真是個好建議!

提供一個好的toString實現可以讓您的類更易於使用,並使使用該類的系統更易於Debug。當一個物件被傳遞給println、printf、字串連線操作符或assert,或者被偵錯程式列印時,toString方法被自動呼叫。即使你從不呼叫物件上的toString,其他人也可能呼叫。

例如,有物件引用的元件可能會在記錄的錯誤訊息中包含物件的字串表示形式。如果您未能重寫toString,則訊息可能幾乎毫無用處。

理想情況下,字串應該是自解釋的
出現以下失敗報告是非常惱人的:

Assertion failure: expected {abc, 123}, but was {abc, 123}.

在實現toString方法時,必須做出的一個重要決定是是否在文件中指定返回值的格式。

建議對值類(如電話號碼或矩陣)執行此操作。指定格式的優點是,它可以作為物件的標準、明確、可讀的表示。這種表示可以用於輸入和輸出,也可以用於持久的人類可讀資料物件,例如CSV檔案。

指定toString返回值的格式的缺點是,一旦指定了它,假設類被廣泛使用,那麼您將終身使用它。程式設計師將編寫程式碼來解析表示、生成表示並將其嵌入持久資料。如果您在將來的版本中更改表示形式,您將破壞它們的程式碼和資料,它們將可能出現錯誤。通過選擇不指定格式,可以保留在後續版本中新增資訊或改進格式的靈活性。

無論您是否決定指定格式,您都應該清楚地記錄您的意圖。如果指定格式,則應該精確地指定格式。例如,下面是一個toString方法,用於第11項中的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);
} 

如果您決定不指定格式,文件註釋應如下所示:

/**
 * 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() { ... } 

無論是否指定格式,都應提供對toString返回的值中包含的資訊的程式設計訪問。例如,PhoneNumber類應該包含區號、字首和行號的訪問器。如果您沒有做,需要這些資訊的程式設計師就得強解析這字串。除了降低效能和為程式設計師做不必要的工作之外,這個過程還容易出錯,如果更改格式,會導致脆弱的系統崩潰。由於未能提供訪問器,您將字串格式轉換為事實上的API,即使您指定它可能會更改。

在靜態工具類中編寫toString方法是沒有意義的。
也不應該在大多數列舉型別中編寫toString方法,因為Java為提供了其他的好方法。但是,您應該在其子類共享公共字串表示的任何抽象類中編寫toString方法。例如,大多數集合實現上的toString方法都是從抽象集合類繼承的。
Google的開源AutoValue工具(在第10項中討論)將為您生成toString方法,大多數ide也是如此。這些方法非常適合告訴您每個欄位的內容,但並不專門針對類的含義。因此,例如,對PhoneNumber類使用自動生成的toString方法是不合適的(因為PhoneNumber有一個標準的字串表示),但是對於我們的Potion類來說,它是完全可以接受的。也就是說,自動生成的toString方法比從Object繼承的方法要好得多,後者不告訴您任何關於物件值的資訊。
總而言之,在您編寫的每個可例項化類中重寫物件的toString實現,除非已經有超類這樣做了。它使類更易於使用並有助於除錯。toString方法應該以一種美觀的格式返回對物件的簡潔、有用的描述。