Skip to content

13. Mise en forme et localisation en Java

Table des matières


Ce chapitre fournit un traitement approfondi et pratique de la mise en forme en Java 21.

13.1 Mise en forme des chaînes

13.1.1 String.format et formatted

String.format() crée des chaînes formatées en utilisant des substituts de type printf.

Il est sensible au locale et retourne une nouvelle String immuable.

String result = String.format("The User: %s | Score: %d", "Bob", 42);
System.out.println(result);

// Or

System.out.println("The User: %s | Score: %d".formatted("Bob", 42));

Sortie :

The User: Bob | Score: 42

Caractéristiques clés :

  • Utilise des spécificateurs de format tels que %s (tout type, généralement des chaînes), %d (valeurs entières), %f (valeurs à virgule flottante).
  • Ne modifie pas les chaînes existantes.
  • Lance IllegalFormatException si les arguments ne correspondent pas au format.
  • Est sensible au locale lorsqu’un Locale est fourni.
String price = String.format(Locale.GERMANY, "%.2f", 1234.5);
// Sortie (locale allemand) : 1234,50

13.1.1.1 Indicateurs pour nombres à virgule flottante

%f est utilisé pour formater les nombres à virgule flottante (float, double, BigDecimal) en notation décimale.

System.out.printf("%f", 12.345);
12.345000
  • Affiche toujours 6 chiffres après le séparateur décimal par défaut.
  • Utilise l’arrondi (et non la troncature).
  • Est sensible au locale pour le séparateur décimal.

13.1.1.2 Précision (.n)

La précision définit le nombre de chiffres affichés après le séparateur décimal.

System.out.printf("%.2f", 12.345);
12.35
  • %.0f n’affiche aucun chiffre décimal.
  • L’arrondi est appliqué.
  • La précision est appliquée avant le remplissage de la largeur.

13.1.1.3 Largeur (m)

La largeur définit le nombre total minimal de caractères dans la sortie.

System.out.printf("%8.2f", 12.34);
   12.34
  • Remplit avec des espaces par défaut.
  • Si la valeur est plus longue, la largeur est ignorée (elle ne tronque jamais).
  • Le remplissage est appliqué à gauche par défaut.

13.1.1.4 Indicateur de remplissage par zéro 0

L’indicateur 0 remplace le remplissage par des espaces par des zéros.

System.out.printf("%08.2f", 12.34);
00012.34
  • Nécessite une largeur.
  • Les zéros sont insérés après le signe.
  • Ignoré si la justification à gauche est présente (indicateur -).

13.1.1.5 Justification à gauche Indicateur -

L’indicateur - aligne la valeur à gauche à l’intérieur de la largeur.

System.out.printf("%-8.2f", 12.34);
12.34   
  • Le remplissage est déplacé vers la droite.
  • Écrase le remplissage par zéro.

13.1.1.6 Signe explicite Indicateur +

L’indicateur + force l’affichage du signe pour les nombres positifs.

System.out.printf("%+8.2f", 12.34);
   +12.34
  • Les nombres négatifs affichent déjà -.
  • Écrase l’indicateur espace (qui affiche un espace en tête pour les valeurs positives).

13.1.1.7 Parenthèses pour les négatifs Indicateur (

L’indicateur ( formate les nombres négatifs en utilisant des parenthèses.

System.out.printf("%(8.2f", -12.34);
 (12.34)
  • N’affecte que les valeurs négatives.
  • Rarement utilisé en pratique.

13.1.1.8 Combinaison des indicateurs

System.out.printf("%+010.2f", 12.34);
+000012.34

Ordre d’évaluation (simplifié) :

  • La précision est appliquée.
  • Le signe est traité.
  • La largeur est appliquée.
  • Le remplissage (espaces ou zéros) est appliqué.

13.1.1.9 Effets du Locale

System.out.printf(Locale.FRANCE, "%,.2f", 12345.67);
12 345,67

Les séparateurs décimaux et de groupement dépendent du Locale actif.

13.1.1.10 Erreurs courantes

  • %f utilise 6 décimales par défaut si aucune précision n’est spécifiée.
  • La largeur ne tronque jamais la sortie ; elle ne fait qu’ajouter du remplissage si nécessaire.
  • L’indicateur 0 est ignoré lorsque - est présent.
  • + écrase l’indicateur espace.
  • Le groupement et les séparateurs dépendent du Locale.

13.1.2 Valeurs de texte personnalisées et échappement

Certains caractères ont une signification particulière dans les chaînes de format et doivent être échappés.

  • %% → signe pourcentage littéral.
  • \n, \t → échappements Java standards.
String msg = String.format("Completion: %d%%%nStatus: OK", 100);
System.out.println(msg);

Sortie :

Completion: 100%
Status: OK

Note

Un seul % sans spécificateur valide provoque une IllegalFormatException à l’exécution.

13.2 Mise en forme des nombres

13.2.1 NumberFormat

NumberFormat est une classe abstraite utilisée pour formater et analyser les nombres de manière sensible au locale.

NumberFormat nf = NumberFormat.getInstance(Locale.FRANCE);
System.out.println(nf.format(1234567.89));

Important

  • Les méthodes factory déterminent le style de formatage (général, entier, monnaie, pourcentage, compact, ...).
  • Le formatage dépend du Locale fourni.
  • NumberFormat (et DecimalFormat) ne sont pas thread-safe.

13.2.2 Localisation des nombres

La localisation des nombres affecte les séparateurs décimaux, les séparateurs de groupement et les symboles monétaires.

NumberFormat nfUS = NumberFormat.getInstance(Locale.US);
NumberFormat nfIT = NumberFormat.getInstance(Locale.ITALY);

System.out.println(nfUS.format(1234.56)); // 1,234.56
System.out.println(nfIT.format(1234.56)); // 1.234,56

13.2.3 DecimalFormat et NumberFormat

DecimalFormat est une sous-classe concrète de NumberFormat qui offre un contrôle fin de la mise en forme numérique à l’aide de patterns.

NumberFormat définit un formatage sensible au locale via des méthodes factory, tandis que DecimalFormat permet un contrôle explicite basé sur des patterns.

NumberFormat nf = NumberFormat.getInstance(Locale.US);
DecimalFormat df = (DecimalFormat) nf;

Ou directement :

DecimalFormat df = new DecimalFormat("#,##0.00");

Note

  • DecimalFormat est mutable (on peut modifier le pattern, les symboles, etc.).
  • DecimalFormat n’est pas thread-safe.
  • Le formatage est sensible au locale via DecimalFormatSymbols.

13.2.4 Structure du pattern DecimalFormat

Un pattern peut contenir une sous-structure positive et une sous-structure négative optionnelle, séparées par ;.

#,##0.00;(#,##0.00)

Note

  • Première partie → nombres positifs.
  • Seconde partie → nombres négatifs.
  • Si la partie négative est omise, les nombres négatifs utilisent automatiquement un - en tête.

13.2.5 Le symbole 0 (chiffre obligatoire)

Le symbole 0 force l’affichage d’un chiffre, en complétant avec des zéros si nécessaire.

DecimalFormat df = new DecimalFormat("0000.00");
System.out.println(df.format(12.3));
0012.30
  • Contrôle le nombre minimal de chiffres.
  • Complète avec des zéros si le nombre contient moins de chiffres.
  • Utile pour des sorties à largeur fixe ou alignées.

13.2.6 Le symbole # (chiffre optionnel)

Le symbole # affiche un chiffre uniquement s’il existe.

DecimalFormat df = new DecimalFormat("####.##");
System.out.println(df.format(12.3));
12.3
  • Supprime les zéros initiaux.
  • Supprime les zéros finaux inutiles.
  • Adapté à un formatage « convivial ».

13.2.7 Combiner 0 et #

Les patterns combinent souvent les deux symboles pour plus de flexibilité.

DecimalFormat df = new DecimalFormat("#,##0.##");
System.out.println(df.format(12));
System.out.println(df.format(12.5));
System.out.println(df.format(12345.678));
12
12.5
12,345.68

Explication du pattern :

#,##0 . ##
 ^  ^    ^
 |  |    |
 |  |    └─ chiffres fractionnaires optionnels (#)
 |  └───── chiffre entier obligatoire (0)
 └──────── pattern de groupement (,)
  • Au moins un chiffre entier est garanti (le 0).
  • Les chiffres sont regroupés par milliers à l’aide du séparateur de groupement.
  • Les chiffres fractionnaires sont optionnels (jusqu’à deux).

13.2.8 Séparateurs décimaux et de groupement

Dans les patterns :

  • . → séparateur décimal.
  • , → séparateur de groupement.

Les symboles effectivement utilisés à l’exécution dépendent du Locale (par exemple, virgule vs point).

13.2.9 DecimalFormatSymbols : symboles de format spécifiques au Locale

DecimalFormatSymbols symbols =
        DecimalFormatSymbols.getInstance(Locale.FRANCE);

DecimalFormat df =
        new DecimalFormat("#,##0.00", symbols);

System.out.println(df.format(1234.5));
1 234,50
  • Contrôle les séparateurs décimaux et de groupement.
  • Contrôle le signe moins et le symbole monétaire.
  • Contrôle les chaînes NaN et Infinity.

13.2.10 Patterns spéciaux de DecimalFormat

0.###E0   notation scientifique
###%      pourcentage
¤#,##0.00 monnaie (¤ est le symbole monétaire)

13.2.11 Règles et erreurs courantes

  • DecimalFormat est une sous-classe de NumberFormat.
  • 0 force les chiffres, # non.
  • Les patterns contrôlent le formatage, pas le mode d’arrondi (utiliser setRoundingMode()).
  • Le groupement fonctionne uniquement si le séparateur (généralement ,) est présent dans le pattern.
  • Le parsing peut réussir partiellement sans erreur si des caractères finaux suivent un nombre valide.
  • DecimalFormat est mutable et non thread-safe.

13.3 Analyse (parsing) des nombres

L’analyse convertit un texte localisé en valeurs numériques. Par défaut, l’analyse est permissive.

NumberFormat nf = NumberFormat.getInstance(Locale.FRANCE);
Number n = nf.parse("12 345,67abc"); // analyse 12345.67
  • L’analyse s’arrête au premier caractère invalide.
  • Le texte final est ignoré sauf vérification explicite.

13.3.1 Parsing avec DecimalFormat

DecimalFormat peut également analyser des nombres. L’analyse est permissive par défaut.

DecimalFormat df = new DecimalFormat("#,##0.##");
Number n = df.parse("1,234.56abc");
  • L’analyse s’arrête au premier caractère invalide.
  • Le texte final est ignoré s’il est présent.

Pour imposer une analyse stricte :

df.setParseStrict(true);

13.3.2 CompactNumberFormat

La mise en forme compacte abrège les grands nombres pour une meilleure lisibilité humaine.

  • Prend en charge les styles SHORT et LONG.
  • Utilise des abréviations dépendantes du locale (par exemple K, M, « million »).
NumberFormat cnf =
        NumberFormat.getCompactNumberInstance(
                Locale.US, NumberFormat.Style.SHORT);

System.out.println(cnf.format(1_200));        // 1.2K
System.out.println(cnf.format(5_000_000));    // 5M

NumberFormat cnf1 =
        NumberFormat.getCompactNumberInstance(
                Locale.US, NumberFormat.Style.SHORT);

NumberFormat cnf2 =
        NumberFormat.getCompactNumberInstance(
                Locale.US, NumberFormat.Style.LONG);

System.out.println(cnf1.format(315_000_000));   // 315M
System.out.println(cnf2.format(315_000_000));   // 315 million

13.4 Mise en forme des dates et heures

13.4.1 DateTimeFormatter

Java 21 repose sur java.time et DateTimeFormatter pour la mise en forme moderne des dates et heures.

DateTimeFormatter f =
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
System.out.println(LocalDateTime.now().format(f));

Propriétés principales :

  • Immuable.
  • Thread-safe.
  • Sensible au locale.

13.4.2 Symboles standard de date et d’heure

y   année
M   numéro du mois (ou nom avec plus de lettres)
d   jour du mois
E   nom du jour
H   heure (0–23)
h   heure (1–12)
m   minute
s   seconde
a   indicateur AM/PM
z   fuseau horaire

13.4.3 datetime.format vs formatter.format

Les deux méthodes sont fonctionnellement identiques :

date.format(formatter);
formatter.format(date);
  • date.format(formatter) → préféré pour la lisibilité (données d’abord, puis formatage).
  • formatter.format(date) → parfois pratique dans un code fonctionnel ou avec des formatters réutilisables.

13.4.4 Localisation des dates

Les styles localisés adaptent l’affichage des dates aux normes culturelles.

DateTimeFormatter fullIt =
        DateTimeFormatter
                .ofLocalizedDate(FormatStyle.FULL)
                .withLocale(Locale.ITALY);

DateTimeFormatter shortIt =
        DateTimeFormatter
                .ofLocalizedDate(FormatStyle.SHORT)
                .withLocale(Locale.ITALY);

LocalDate today = LocalDate.of(2025, 12, 17);

System.out.println(today.format(fullIt));
System.out.println(today.format(shortIt));

Sortie possible :

mercoledì 17 dicembre 2025
17/12/25

13.5 Internationalisation (i18n) et localisation (l10n)

13.5.1 Locales

Un Locale définit la langue, le pays et une variante optionnelle.

Locale l1 = Locale.US;
Locale l2 = Locale.of("fr", "FR");
Locale l3 = new Locale.Builder()
        .setLanguage("en")
        .setRegion("US")
        .build();

Formats de Locale :

  • en (it, fr, etc.) : code langue en minuscules.
  • en_US (fr_CA, it_IT, etc.) : code langue en minuscules + underscore + code pays en majuscules.

13.5.2 Catégories de Locale

Les catégories de Locale séparent la mise en forme de la langue de l’interface utilisateur.

Locale.Category permet à Java d’utiliser différents Locale par défaut selon les usages.

Il existe deux catégories :

Catégorie Utilisée pour
FORMAT Nombres, dates, monnaie, autre formatage
DISPLAY Texte lisible (UI, noms, messages)

13.5.3 Exemple réel

Un utilisateur français vivant en Allemagne peut souhaiter :

  • Nombres et dates → format allemand.
  • Langue de l’interface → français.

Avant Java 7, cela n’était pas possible.

Locale.setDefault(Locale.Category.FORMAT, Locale.GERMANY);
Locale.setDefault(Locale.Category.DISPLAY, Locale.FRANCE);

Exemples d’effets :

Aspect Résultat (exemple)
Nombres 1.234,56
Dates 31.12.2025
Monnaie
Texte UI Français
Noms des mois décembre
Noms des pays Allemagne

13.6 Properties et Resource Bundles

Les resource bundles externalisent le texte et permettent la localisation sans modifier le code.

ResourceBundle rb =
        ResourceBundle.getBundle("messages", Locale.GERMAN);

String msg = rb.getString("welcome");

13.6.1 Règles de résolution des Resource Bundles

Java recherche les bundles selon un ordre de repli strict. Par exemple, avec le nom de base messages et le locale de_DE :

  • messages_de_DE.properties
  • messages_de.properties
  • messages.properties

Si aucun n’est trouvé → MissingResourceException.

Note

Les fichiers .properties traditionnels sont spécifiés en ISO-8859-1 ; les caractères non ASCII doivent être encodés via des échappements Unicode (par exemple \u00E9 pour é), sauf si des mécanismes de chargement alternatifs sont utilisés.

13.7 Règles et erreurs courantes

  • DateTimeFormatter est immuable et thread-safe.
  • NumberFormat / DecimalFormat sont mutables et non thread-safe.
  • Modifier le Locale affecte la manière dont les valeurs sont formatées et analysées, et non les valeurs numériques ou temporelles sous-jacentes.
  • L’analyse avec NumberFormat ou DecimalFormat peut réussir partiellement sans exception si du texte supplémentaire suit un nombre valide.
  • java.time remplace la plupart des usages des anciennes API java.util.Date / Calendar dans le code moderne et à l’examen.