Comment utiliser la méthode toString() en Java

La méthode toString() de la classe Object est appelée automatiquement par Java dès qu'un objet est converti en chaîne de caractères — dans un System.out.println, une concaténation ou un log. Bien la redéfinir rend le code beaucoup plus facile à déboguer.

Le comportement par défaut

Sans override, Object.toString() renvoie une chaîne peu utile : le nom complet de la classe, suivi de @ et du hash code en hexadécimal :

public class Utilisateur {
    String nom;
    int age;
}

Utilisateur u = new Utilisateur();
System.out.println(u);
// → Utilisateur@1540e19d

Ce n'est quasiment jamais ce qu'on veut voir dans un log ou une erreur.

Redéfinir toString() manuellement

Utilisez toujours l'annotation @Override — elle garantit que la signature est correcte :

public class Utilisateur {
    private final String nom;
    private final int age;

    public Utilisateur(String nom, int age) {
        this.nom = nom;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Utilisateur{nom='" + nom + "', age=" + age + "}";
    }
}

System.out.println(new Utilisateur("Alice", 30));
// → Utilisateur{nom='Alice', age=30}

Le format conventionnel est NomDeClasse{champ1=val1, champ2=val2}, facilement lisible et uniforme.

Avec String.format ou StringBuilder

Pour des classes avec beaucoup de champs, préférez String.format (plus lisible) ou StringBuilder (plus rapide en boucle serrée) :

@Override
public String toString() {
    return String.format("Utilisateur{nom='%s', age=%d, email='%s'}", nom, age, email);
}

Utiliser un record (Java 16+)

Les record génèrent automatiquement une implémentation de toString(), d'equals() et de hashCode(). C'est la manière la plus concise de décrire une classe de données :

public record Utilisateur(String nom, int age) { }

System.out.println(new Utilisateur("Alice", 30));
// → Utilisateur[nom=Alice, age=30]

Avec Lombok

Si vous utilisez Lombok, l'annotation @ToString suffit :

import lombok.ToString;

@ToString
public class Utilisateur {
    private String nom;
    private int age;
    @ToString.Exclude private String motDePasse; // exclu du toString
}

L'option @ToString.Exclude est cruciale pour éviter de logger des données sensibles (mots de passe, jetons, numéros de carte).

Génération automatique dans l'IDE

  • IntelliJ IDEA : Alt + InserttoString(), puis choisir le template.
  • Eclipse : clic droit sur la classe → Source → Generate toString().
  • VS Code (extension Java) : Ctrl + . sur le nom de la classe → Generate toString().

Bonnes pratiques

  1. Ne jamais inclure de données sensibles (mots de passe, tokens). Préférez "***" ou masquez les premiers chiffres.
  2. Attention aux collections circulaires : si un objet A contient B et B contient A, toString() entrera en récursion infinie. Cassez la boucle avec un marqueur ou excluez le champ.
  3. Évitez les appels coûteux : toString est souvent appelé dans des logs à chaud. Pas de requête SQL ni de lecture de fichier à l'intérieur.
  4. Assurez la cohérence avec equals() : si deux objets sont égaux, leur toString devrait être identique.

Cas particulier : énumérations

Les enum Java ont un toString() par défaut qui renvoie leur nom. Vous pouvez le redéfinir pour obtenir un affichage plus lisible :

public enum Statut {
    ACTIF("Actif"),
    EN_ATTENTE("En attente"),
    SUPPRIME("Supprimé");

    private final String libelle;
    Statut(String libelle) { this.libelle = libelle; }

    @Override
    public String toString() { return libelle; }
}

En résumé : pour toute classe que vous allez logger, déboguer ou afficher, une implémentation explicite (ou générée) de toString() est incontournable.