Une chaîne mal formatée peut rendre un message illisible, afficher un prix faux ou compliquer inutilement la maintenance d’une application Java. Je présente ici les méthodes les plus utiles pour construire des textes propres avec String.format(), formatted() et printf(), avec les spécificateurs essentiels, la gestion des locales, les dates et les erreurs courantes.
Les repères essentiels pour formater une chaîne en Java
- String.format() renvoie une nouvelle chaîne à partir d’un modèle et de valeurs.
- %s, %d, %.2f, %tF et %n couvrent la majorité des besoins courants.
- Locale est indispensable pour afficher correctement les nombres, les devises et les dates selon le pays.
- formatted() est une écriture pratique lorsque le modèle est déjà stocké dans une chaîne.
- Une erreur de type ou un spécificateur incorrect peut provoquer une IllegalFormatException.
Comprendre les principales méthodes de formatage
La méthode la plus connue est String.format(). Elle reçoit une chaîne modèle, puis les valeurs à insérer à la place des marqueurs comme %s ou %d.
String nom = "Camille";
int messages = 8;
String texte = String.format(
"Bonjour %s, vous avez %d nouveaux messages.",
nom,
messages
);
System.out.println(texte);
Le résultat sera « Bonjour Camille, vous avez 8 nouveaux messages. ». J’utilise cette approche lorsque le texte doit être réutilisé, testé ou composé à partir de plusieurs valeurs. Elle reste bien plus lisible qu’une longue succession d’opérateurs +.
Depuis Java 15, une chaîne peut aussi appeler directement formatted(). Le modèle devient alors plus facile à lire, surtout lorsqu’il est défini sur plusieurs lignes ou conservé dans une constante.
String modèle = "Utilisateur : %s | Score : %d";
String résultat = modèle.formatted("Camille", 92);
Pour afficher immédiatement une valeur dans la console, printf() convient très bien. Cette méthode formate et écrit le résultat sans créer explicitement une variable intermédiaire.
System.out.printf("Température : %.1f °C%n", 21.6);
La différence est simple. String.format() et formatted() renvoient une chaîne, tandis que printf() écrit directement vers une sortie comme la console. Pour un message destiné à une API, un fichier ou une interface, je préfère généralement produire la chaîne avec String.format().
Maîtriser les spécificateurs les plus utiles
Un spécificateur commence par le caractère %. Il indique à Java comment convertir la valeur correspondante. Voici les marqueurs que l’on rencontre le plus souvent dans les applications.
| Spécificateur | Usage | Exemple |
|---|---|---|
%s |
Chaîne ou objet converti en texte | "Nom : %s" |
%d |
Nombre entier | "Total : %d" |
%f |
Nombre décimal | "Valeur : %f" |
%.2f |
Décimal avec deux chiffres après la virgule | "Prix : %.2f" |
%b |
Valeur booléenne | "Actif : %b" |
%c |
Caractère | "Lettre : %c" |
%tF |
Date au format ISO | "Date : %tF" |
%n |
Saut de ligne adapté au système | "Ligne 1%nLigne 2" |
%% |
Caractère pourcentage littéral | "Progression : %d%%" |
La précision est particulièrement pratique pour les prix et les mesures. Avec %.2f, la valeur 19.9 devient 19,90 dans une locale française, à condition de fournir la locale appropriée.
double prix = 19.9;
String affichage = String.format(Locale.FRANCE, "Prix : %.2f €", prix);
Pour aligner du texte ou compléter un nombre avec des zéros, on peut ajouter une largeur ou un indicateur. Par exemple, %08d affiche un entier sur huit caractères en ajoutant des zéros à gauche.
String référence = String.format("Commande-%08d", 247);
System.out.println(référence);
// Commande-00000247
Les arguments peuvent aussi être référencés par position. C’est utile lorsqu’une valeur doit apparaître plusieurs fois ou lorsque l’ordre naturel du texte ne correspond pas à celui des paramètres.
String message = String.format(
"%1$s a obtenu %2$d points. Bravo %1$s !",
"Nora",
96
);
Je conseille toutefois de ne pas multiplier ces indices dans un message court. Ils deviennent vite difficiles à relire. Dans un modèle plus long, ils évitent néanmoins les doublons et réduisent le risque d’inverser les valeurs.
Formater correctement les nombres, les dates et les locales
Le formatage ne dépend pas seulement du type Java. Il dépend aussi de la locale, c’est-à-dire des règles régionales appliquées aux nombres, aux séparateurs, aux mois et parfois aux symboles monétaires.
import java.util.Locale;
double montant = 1234567.89;
String français = String.format(
Locale.FRANCE,
"%,.2f €",
montant
);
String anglais = String.format(
Locale.US,
"%,.2f $",
montant
);
Selon la locale, le séparateur des milliers et celui des décimales ne seront pas les mêmes. Pour une application utilisée en France, je préfère passer explicitement Locale.FRANCE plutôt que de dépendre de la configuration de la machine qui exécute le programme.
Les dates peuvent être formatées avec les conversions temporelles de Formatter, par exemple %tF pour obtenir une date au format année-mois-jour.
import java.time.LocalDate;
LocalDate date = LocalDate.of(2026, 9, 12);
String résultat = String.format("Date d'inscription : %tF", date);
Pour une application récente, je recommande néanmoins DateTimeFormatter dès que le besoin devient précis, notamment pour afficher un mois en français, un fuseau horaire ou une date destinée à une interface. String.format() est pratique pour un message simple, mais il ne remplace pas un outil spécialisé pour les règles métier.
Les montants financiers demandent la même prudence. Un format comme %.2f contrôle l’affichage, mais ne corrige pas les erreurs d’arrondi d’un calcul effectué avec double. Pour de l’argent, le choix de BigDecimal reste plus important que le simple format visuel.
Éviter les erreurs qui apparaissent à l’exécution
Le compilateur ne vérifie pas toujours qu’un spécificateur correspond au type fourni. Une faute peut donc apparaître seulement lorsque le code est exécuté, avec une exception comme IllegalFormatConversionException ou MissingFormatArgumentException.
int quantité = 12;
// Incorrect, car %f attend un nombre décimal
String texte = String.format("Quantité : %f", quantité);
Pour un entier, utilisez %d. Pour un nombre décimal, utilisez %f. Cette distinction semble évidente, mais elle est souvent oubliée lorsque les valeurs arrivent d’un formulaire, d’un fichier JSON ou d’une base de données.
Le caractère pourcentage est un autre piège classique. Dans un modèle, % lance une interprétation de formatage. Pour afficher le symbole lui-même, il faut écrire %%.
int progression = 75;
String texte = String.format("Téléchargement terminé à %d%%", progression);
Un argument null ne provoque pas forcément une erreur avec %s, car Java peut afficher le texte « null ». Cela peut cependant produire un message peu professionnel. Dans mes propres modèles, je décide toujours à l’avance si une valeur absente doit devenir une chaîne vide, un libellé explicite ou une véritable erreur.
Enfin, les modèles provenant d’une saisie externe doivent être traités avec prudence. Un utilisateur ne devrait pas pouvoir contrôler directement la chaîne de format passée à String.format(), car des spécificateurs inattendus peuvent provoquer des erreurs ou exposer des informations dans un message généré.
Choisir entre concaténation, formatage et interpolation
Il n’existe pas une seule bonne méthode pour toutes les situations. Pour un texte très court, la concaténation reste parfaitement acceptable. Pour plusieurs valeurs ou un alignement précis, les spécificateurs rendent le résultat beaucoup plus clair.
| Solution | Point fort | Limite | Usage conseillé |
|---|---|---|---|
Concaténation avec +
|
Simple et directe | Devient vite confuse | Deux ou trois valeurs simples |
String.format() |
Modèle lisible et contrôle précis | Syntaxe à mémoriser | Messages structurés, rapports et sorties utilisateur |
formatted() |
Très naturel sur une chaîne existante | Nécessite une version Java suffisamment récente | Constantes et modèles réutilisables |
printf() |
Affichage immédiat | Ne renvoie pas une chaîne utilisable ailleurs | Console et petits outils en ligne de commande |
StringBuilder |
Construction progressive | Plus verbeux | Texte assemblé dans une boucle ou un processus complexe |
Les performances sont rarement le premier problème avec quelques appels isolés. En revanche, appeler String.format() des milliers de fois dans une boucle peut coûter plus cher qu’une construction plus spécialisée. Pour une sortie massive, je mesure avant d’optimiser, puis j’examine StringBuilder, les flux de sortie ou une solution dédiée.
Pour les logs, je déconseille aussi de formater inutilement un message qui ne sera jamais écrit parce que le niveau de journalisation est désactivé. Les frameworks modernes proposent souvent un formatage différé ou paramétré. Cela évite de construire la chaîne avant même de savoir si elle sera utilisée.
Adopter une méthode fiable dans un projet Java
Mon approche est simple. Je commence par choisir le type réel de chaque valeur, puis je sélectionne le spécificateur adapté. Ensuite, je fixe explicitement la locale lorsque le message contient un nombre, une date ou une monnaie destinée à un utilisateur.
- Écrivez le message final avec ses espaces et sa ponctuation.
- Remplacez chaque valeur variable par un spécificateur lisible.
- Vérifiez l’ordre et le type des arguments.
- Ajoutez une locale pour les données dépendantes du pays.
- Testez les valeurs limites, notamment zéro, les nombres négatifs et les valeurs absentes.
Un test minimal doit vérifier non seulement que le code s’exécute, mais aussi que le texte produit est exactement celui attendu. Une différence comme 1 234,50 € au lieu de 1234.50 € peut être anodine dans un journal technique, mais problématique sur une facture ou dans une interface française.
Le bon format dépend surtout du message final
Pour la plupart des besoins, String.format() constitue le meilleur point de départ. Utilisez formatted() lorsque le modèle appartient déjà à une chaîne, printf() pour une sortie immédiate et StringBuilder pour une construction progressive.
Le détail qui fait réellement la différence reste la cohérence entre le type, la locale et l’usage du message. Un formatage propre ne consiste pas seulement à placer une valeur dans une phrase. Il doit produire un texte exact, lisible et adapté à la personne qui le recevra.