<code>toString()</code> in Java

toString() returns a human-readable representation of an object. Every class inherits one from Object β€” the default prints ClassName@1a2b3c, useless for debugging. Override it on anything you'll see in logs, exception messages or debugger output.

Default vs overridden

class UserNoToString {
    String name; int age;
}
new UserNoToString().toString();     // "UserNoToString@5e8c92f4" β€” the hashCode in hex

class User {
    String name; int age;
    @Override
    public String toString() {
        return "User{name=" + name + ", age=" + age + "}";
    }
}
new User().toString();               // "User{name=null, age=0}"

Records: automatic

public record User(String name, int age) {}
new User("Alice", 30).toString();    // "User[name=Alice, age=30]"

Conventions

  • Include the class name β€” so you can tell types apart in logs.
  • Include every field that matters for identity or debugging.
  • Skip large byte arrays, streams, and secrets (passwords, tokens).
  • Keep it short enough to fit on one log line.

Where it matters most

log.error("Payment failed for " + order);           // calls order.toString()
throw new IllegalStateException("invalid " + config); // message shows config
System.out.println(Map.of("a", user));                // map.toString recursively calls values

Formatting tools

// Commons Lang
ToStringBuilder.reflectionToString(this);

// Manual with StringBuilder
return new StringBuilder("User{")
    .append("name=").append(name)
    .append(", age=").append(age)
    .append('}')
    .toString();

// Java 15+ text blocks for multi-line
return """
       User {
         name: %s
         age:  %d
       }
       """.formatted(name, age);

Common mistakes

  • Leaking secrets β€” Credentials.toString() must not show the password. Replace with ***.
  • Recursive toString β€” parent ↔ child references blow the stack. Print IDs only for references to other managed objects.
  • Expensive toString β€” remember it's called inside log statements that might be disabled. Use a lazy Supplier or SLF4J's {} placeholder.

Related

Pillar: Java methods. See also records, equals & hashCode.