Méthode Java toString()
Redéfinissez toString() dans vos classes Java pour produire des représentations textuelles utiles au débogage et à la journalisation.
toString est la méthode que System.out.println, la concaténation de chaînes et votre débogueur appellent lorsqu'ils ont besoin de représenter un objet sous forme de texte. La version par défaut — héritée d'Object — renvoie le nom de la classe suivi d'un hash hexadécimal illisible. Redéfinir toString est l'une des choses les moins coûteuses et les plus rentables que vous puissiez faire pour ceux qui liront vos logs et vos traces de pile (souvent une version future de vous-même).
Où est-il appelé
Vous n'appelez presque jamais toString directement. Il est invoqué implicitement chaque fois qu'un objet est converti en texte :
Point p = new Point(3, 4);
System.out.println(p); // calls p.toString()
String msg = "got " + p; // calls p.toString()
log.info("point: {}", p); // calls p.toString()Partout où un Object apparaît dans un contexte qui attend un String, toString s'exécute. C'est pourquoi la valeur par défaut est si décevante — elle apparaît partout et ne vous dit rien d'utile.
La valeur par défaut
Object.toString() renvoie getClass().getName() + "@" + Integer.toHexString(hashCode()). Ainsi, une classe ordinaire affiche quelque chose comme com.example.Point@1540e19d. Le nom de classe est correct ; le hexadécimal est le hash d'identité, qui est inutile quand vous essayez de comprendre ce que contiennent les champs de l'objet.
Une bonne redéfinition
Une bonne méthode toString est concise, non ambiguë et contient les données qu'un lecteur voudrait voir :
@Override
public String toString() {
return "Point[x=" + x + ", y=" + y + "]";
}Quelques conventions qui valent la peine d'être suivies :
- Incluez le nom de la classe. Quand une ligne de log mélange des objets, savoir de quel type il s'agit est important.
- Utilisez une forme stable et analysable.
Class[field=value, field=value]est ce que les records et la plupart des bibliothèques Java modernes utilisent. C'est lisible et facile à chercher avec grep. - Affichez les champs qui importent — généralement ceux présents dans
equals. Omettez les champs volumineux (un blob de 10 Mo, uneConnection). - N'incluez pas de données sensibles. Mots de passe, jetons, données personnelles — laissez-les de côté, ou masquez-les.
toStringfinit dans les fichiers de logs.
Avec String.format ou les blocs de texte
Pour plus de trois ou quatre champs, String.format (ou un bloc de texte) se lit mieux que la concaténation :
@Override
public String toString() {
return String.format("User[id=%d, name=%s, role=%s]", id, name, role);
}Ne le rendez pas coûteux
toString est appelé plus souvent que vous ne le pensez — les frameworks de journalisation rendent les arguments paresseusement, mais suffisamment tôt pour qu'un toString en O(n²) sur une liste de 100 000 éléments ralentisse réellement votre service. Gardez la sortie bornée. Le toString d'une collection devrait se limiter à un début sensible, avec ... (N more) pour le reste.
Ne lancez pas d'exception depuis toString
Lancer une exception dans toString transforme une ligne de log ordinaire en NullPointerException quelque part d'inattendu — et le problème sous-jacent que vous essayiez de journaliser est perdu. Protégez-vous contre les valeurs nulles :
@Override
public String toString() {
return "Order[id=" + id + ", customer=" + (customer == null ? "<none>" : customer.name()) + "]";
}Les records l'obtiennent gratuitement
Si votre classe est un simple porteur de données, les records génèrent déjà un bon toString :
record Point(int x, int y) {}
System.out.println(new Point(3, 4)); // Point[x=3, y=4]Redéfinir toString est donc surtout utile pour les classes qui ne sont pas des records.
Un exemple complet
La suite
toString produit une description d'un objet. Le prochain chapitre porte sur la production d'une copie d'un objet — clone, Cloneable, et les choix de conception délicats autour des copies superficielles et profondes. Continuez avec le clonage d'objets Java.