Effective Java 3 rdエントリ12は毎回toStringを上書きする

3901 ワード

ObjectはtoStringメソッドの実装を提供していますが、返される文字列は通常、クラスのユーザーが見たいものではありません.クラス名を含み、「at」記号(@)と記号のないハッシュ符号の16進数表現、例えば[email protected]の汎用協定によると、返される文字列は「簡潔だが読みやすい情報表現」であるべきだという.けれどPhoneNumber@163b91簡潔で読みやすいので、議論があるかもしれませんが、707-867-5309と比較すると、非常に情報的ではありません.toString協定は「すべてのサブクラスがこの方法を書き換えることを推奨している」と続けた.良い提案、確かに!
これはequalsとhashCode協定(エントリ10と11)に従うほど重要ではありませんが、クラスの使用をより楽しくし、このクラスを使用するシステムをデバッグしやすくするための良いtoString実装を提供します.オブジェクトがprintln、printf、文字列接続オペレータ、断言、またはデバッグツールによって印刷されると、toStringメソッドは自動的に呼び出されます.オブジェクトのtoStringを呼び出したことがなくても、他の人はできます.たとえば、オブジェクトへの参照があるコンポーネントです.ログエラー情報にオブジェクトの文字列表現が含まれている可能性があります.toSTringを上書きしていないと、情報はほとんど役に立たないかもしれません.
PhoneNumberに良いtoString方法を提供した場合、次のように便利な診断情報を生成することができます.
System.out.println("Failed to connect to " + phoneNumber);
プログラマーは、toStringを上書きしたかどうかにかかわらず、診断情報を生成しますが、そうしない限り、情報は役に立ちません.良いtoStringメソッドを提供する利点は、クラスのインスタンスに加えて、これらのインスタンスが参照するオブジェクト、特にデータセットにまで拡張されます.マッピングを印刷すると{Jenny=PhoneNumber@163b91}または{Jenny=707-867-5309}どちらが見たいですか?
実際に使用する場合、toStringメソッドは、電話番号の例に示すように、オブジェクトに含まれるすべての関心のある情報を返すべきである.オブジェクトが大きい場合、またはステータスが含まれている場合は文字列の表示に役立ちません.これは現実的ではありません.この場合、toStringは、Manhattan residential phone directory(1487536 listings)またはThread[main,5,main]のようなサマリーを返すべきである.理想的には、文字列は言うまでもありません.(Thread例はこの目標に達していない).その文字列表現には、1つのオブジェクトに興味のあるすべての情報が含まれていない非常に嫌なデメリットがあります.検出失敗レポートは次のように見えます.
Assertion failure: expected {abc, 123}, but was {abc, 123}.
TOStringメソッドを実装する場合、ドキュメントに戻り値のフォーマットを指定するかどうかを決定する必要があります.電話番号やマトリクスなどの値タイプにもおすすめです.フォーマットを指定する利点は、標準的、明確、および手動で読み取り可能なオブジェクトとして表されることです.この表現は、入力および出力として使用することができ、CSVファイルなどの手動で読み取り可能なデータオブジェクトを永続化する.フォーマットを指定した場合、通常、マッチングした静的ファクトリまたは構築子を提供するのは良いアイデアです.これにより、プログラマはオブジェクトとその文字列表現の間で容易に変換できます.Javaプラットフォームライブラリの多くの値クラスでは、BigInteger、BigDecimal、および元の箱詰めクラスのほとんどを含むこの方法が採用されています.
TOString戻り値のフォーマットを指定する欠点は、クラスが広く使用されていると仮定して、それを指定すると、一生それを堅持する必要があります.プログラマーはコード解析という表現を作成し、それを生み出し、永続化データに陥れる.もしあなたが将来のリリースでこの表現を変えたら、彼らのコードとデータを破壊すると言ったら、彼らは怒鳴ります.フォーマットを指定しないことで、後続のパブリケーションに情報を追加したり、フォーマットを改善したりする柔軟性を維持できます.
フォーマットを指定するかどうかにかかわらず、意図を明確にドキュメント化する必要があります.このフォーマットを指定したら、正確にそうすべきです.たとえば、エントリ11のPhoneNumberクラスに適合するtoStringメソッドを次に示します.
/** *             。

*           ,     "XXX-YYY-ZZZZ",
*      ,XXX    ,YYY    ,ZZZ     。
*                。
* 
*                      ,          ,         。 
*   ,         123,             0123。
*/ 
@Override public String toString() { 
    return String.format("%03d-%03d-%04d", 
        areaCode, prefix, lineNum); 
}
フォーマットを指定しない場合は、ドキュメントのコメントを次のように読む必要があります.
/** 
*            。                  ,
*            :
* 
* "[Potion #9: type=love, smell=turpentine, look=india ink]" 
*/ 
@Override public String toString() { ... }
この注釈を読むと、プログラマーはフォーマットの詳細に依存してコードを生成したり、データを永続化したりします.フォーマットが変わったら、彼ら自身を責めるしかありません.
フォーマットを指定するかどうかにかかわらず、プログラミングを提供してtoStringの戻り値に含まれる情報を取得します.たとえば、PhoneNumberクラスには、地域コード、接頭辞、および回線番号のアクセサが含まれる必要があります.あまりやらないと、これらの情報を必要とするプログラマーにこの文字列を解析させます.パフォーマンスの低下とプログラマーの不要な作業に加えて、このプロセスはエラーが発生しやすく、このフォーマットを変更すると、脆弱なシステムがクラッシュします.アクセサを提供できませんでした.文字列フォーマットを実際のAPIに変更しました.変更できると指定しても.
静的効用クラスでtoStringメソッドを記述することは何の意味もない(エントリ4).Javaはあなたに非常に良いものを提供しているので、多くの列挙タイプ(エントリ34)でtoStringメソッドを書くべきではありません.しかし、任意の抽象クラスでtoStringメソッドを記述する必要があります.この抽象クラスのサブクラスは共通の文字列表現を共有します.たとえば、ほとんどのデータセット実装におけるtoStringメソッドは、抽象的なデータセットクラスに継承されます.
GoogleのオープンソースAutoValueフレームワークは、エントリ10で議論されているように、toStringメソッドを生成し、多くのIDEも生成します.これらの方法はよく、各ドメインの内容を教えてくれますが、このクラスを指定する意図はありません.したがって、例えば、私たちのPhoneNumberクラス(電話番号には標準的な文字列が表示されているため)のために自動的に生成されるtoStringメソッドを使用するのは適切ではありませんが、私たちのPotionクラスでは、これは完全に受け入れられます.すなわち,オブジェクト値について何も教えていないObjectに継承されたものに対して,自動的に生成されるtoString法が望ましい.
簡単に言えば、あなたが作成したインスタンス化できないクラスごとに、スーパークラスがすでにそうしていない限り、Objectを上書きするtoStringが実現されます.これにより、クラスの使用がより快適になり、デバッグが支援されます.toStringメソッドは、審美的に快適な方法で、短い有用なオブジェクト記述を返すべきである.