Java | Java 標準ライブラリ:toString の使いどころ

Java Java
スポンサーリンク

toString は「中身を一瞬で覗くための窓」

toString()
「このオブジェクトを、人間にとって読みやすい文字列にするとしたら、どう表現するか?」
を返すメソッドです。

System.out.println(obj);
ログ出力
デバッガでの表示

など、「中身をパッと知りたいとき」にほぼ必ず使われます。

toString() をちゃんと作ってあるクラスは、
ログに1行出すだけで「今なにが起きているか」がわかるようになります。
逆に クラス名@ハッシュ値 しか出ないクラスは、トラブルシュートのときに地獄です。


デフォルトの toString と、オーバーライドした場合の違い

デフォルト実装は「使い物にならない」ことが多い

何もオーバーライドしていないときの toString() は、Object クラスの実装が使われます。
これはだいたい

クラス名@ハッシュコード(16進数)

のような文字列です。

例として、何も書いてない User クラスを使ってみます。

public class User {
    String name;
    String email;
}
Java
User user = new User();
user.name = "Taro";
user.email = "taro@example.com";

System.out.println(user);
Java

出力はこんな感じになります。

User@5e2de80c

これ、中身が何も分からないですよね。
バグ調査のときに見ても、ほとんど役に立ちません。

オーバーライドして「状態が読める」ようにする

toString() を自分で書き換える(オーバーライドする)と、
ログや標準出力に「意味のある情報」を出せるようになります。

public class User {

    private final String name;
    private final String email;

    public User(String name, String email) {
        this.name = name;
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{name=" + name + ", email=" + email + "}";
    }
}
Java

同じように System.out.println(user); すると

User{name=Taro, email=taro@example.com}

と出ます。
どのユーザか一目瞭然です。


使いどころ1:ログ・デバッグでの「状況確認」

ログにオブジェクトをそのまま渡す

よくあるのは、ログ出力時です。

User user = ...;
logger.info("ユーザ登録: {}", user);
Java

ここで user.toString() が呼ばれます。
さっきのような User{name=..., email=...} が出てくれたら、
「どのユーザで問題が起きたか」が一瞬で分かります。

toString がデフォルトのままだと

ユーザ登録: User@5e2de80c

となってしまい、「誰?これ」となります。
本番トラブルのときに、この差はかなり大きいです。

デバッグ時に print して確認する

初心者のうちは、System.out.println でデバッグすることが多いと思います。

System.out.println(order);
Java

ここで Order クラスの toString() がきちんと実装されていれば、
中身を1行で確認できます。

public class Order {

    private final long id;
    private final User user;
    private final int totalPrice;

    @Override
    public String toString() {
        return "Order{id=" + id
                + ", user=" + user
                + ", totalPrice=" + totalPrice
                + "}";
    }
}
Java

これなら

Order{id=10, user=User{name=Taro, email=taro@example.com}, totalPrice=12000}

といった具合に、“状態のスナップショット”が簡単に見られます。


使いどころ2:ドメインオブジェクトの「説明書」として

ビジネス的に意味のある表現を返す

toString() は、単なるデバッグ用に限らず、
「人間に見せる文字列表現」として使えることもあります。

例えば Money 値オブジェクト。

public class Money {

    private final int amount;

    public Money(int amount) {
        if (amount < 0) throw new IllegalArgumentException();
        this.amount = amount;
    }

    public int amount() {
        return amount;
    }

    @Override
    public String toString() {
        return amount + "円";
    }
}
Java

これなら

Money m = new Money(1200);
System.out.println(m);  // 1200円
Java

と自然な形で表示できます。

メール本文や簡易レポートなど、
「そのまま人に見せられるフォーマット」がほしいときは、
toString() をそういう表現にしてしまうのも一つの手です。

デバッグ用と「ユーザ向け表示」を分けたい場合

ただし、本格的なアプリでは

ログ・デバッグ用表示
画面や帳票のためのユーザ向け表示

は、別にしたいことも多いです。

その場合は

toString() → 開発者向け(フィールド名付きの素朴な文字列)
toDisplayString() のようなメソッド → ユーザ向けのフォーマット

と分けておく設計もよくあります。


使いどころ3:コレクションや IDE の表示を見やすくする

List や Map に入れたときの見え方

ListMapSystem.out.println したときも、
中身の toString() が使われます。

List<User> users = List.of(
    new User("Taro", "taro@example.com"),
    new User("Hanako", "hanako@example.com")
);

System.out.println(users);
Java

UsertoString() が整っていれば、例えば

[User{name=Taro, email=taro@example.com}, User{name=Hanako, email=hanako@example.com}]

のようにきれいに出ます。

逆に、User@5e2de80cUser@1a2b3c しか出ないと
どの要素が何なのか全く分かりません。

IDE のデバッガ上でも toString が効く

多くの IDE は、デバッガ上でオブジェクトを展開するときに toString() を使います。
フィールドを一つずつ展開しなくても、一発で状態が見えます。

toString が充実していると、
「デバッガでポチポチ展開しまくる時間」がかなり減ります。


どういう情報を含めるべきか(重要な考え方)

基本方針は「クラスの状態が分かること」

迷ったときは、こう自問してください。

このクラスのインスタンスを1行で説明するとしたら、何を書くのが一番伝わるか?

例えば User なら

id(あれば)
name
email

あたりがあれば、かなり情報量があります。

Order なら

id
user の簡単な情報(name など)
合計金額
状態(新規/出荷済みなど)

などが候補です。

機密情報は慎重に扱う

パスワードやクレジットカード番号のような機密情報は、
toString() に含めないか、マスクして表示するのが安全です。

public class User {

    private final String email;
    private final String password; // ハッシュ済みだとしても…

    @Override
    public String toString() {
        return "User{email=" + email + ", password=****}";
    }
}
Java

ログに生のパスワードが出てしまうと、
開発環境とはいえかなり危険です。

大量データを全部書かない

巨大なリストや長大なテキストを持つオブジェクトで、
toString() で全部書いてしまうと

ログがとんでもなく長くなる
デバッガが重くなる

といった問題が出ます。

その場合は

要素数だけを書く(サイズ情報)
最初の数件だけ書く

などにして、量を絞るのも一手です。


悪い toString の例と直し方

悪い例:よく分からないフォーマット

@Override
public String toString() {
    return name + ":" + email + ":" + point;
}
Java

一見情報は出ていますが、
name:email:point というフォーマットを認識しないと読みづらいです。

修正例:

@Override
public String toString() {
    return "User{name=" + name + ", email=" + email + ", point=" + point + "}";
}
Java

「フィールド名=値」の形にしておくと、
ログを見た人が初見でも読みやすくなります。

悪い例:null 安全性を考えていない

@Override
public String toString() {
    return name.toUpperCase() + "(" + email.toLowerCase() + ")";
}
Java

name や email が null の可能性があるなら、
toString() が NullPointerException を投げてしまうリスクがあります。

デバッグ中に toString() が例外を投げると、
それだけで状況が分からなくなります。

安全に書くなら、null を想定しておく方が安心です。

@Override
public String toString() {
    return "User{name=" + String.valueOf(name)
            + ", email=" + String.valueOf(email) + "}";
}
Java

String.valueOf(null)"null" という文字列になるので、
少なくとも例外にはなりません。


まとめ:初心者が意識しておきたい toString のポイント

toString の使いどころを短く整理すると、こうなります。

デバッグやログで、オブジェクトの状態を一瞬で把握するために使う
ドメインオブジェクトの「1行説明」として、人間が読める形で出す
List / Map / デバッガなどでの見やすさを大幅に改善してくれる

そして、実装するときは

クラスの重要なフィールドを分かりやすく並べる
機密情報や巨大データはそのまま出さない
null で例外を出さないように、ある程度安全側に書く

あたりを意識しておくと安心です。

タイトルとURLをコピーしました