Formattazione delle stringhe in Java
Formatta le stringhe Java con String.format e System.out.printf usando specificatori come %s, %d, %f, %n.
La concatenazione (+) va bene per stringhe brevi e semplici. Nel momento in cui si vuole fissare un numero a un certo numero di cifre decimali, allineare colonne tramite padding, incorporare una data con un layout coerente, o in generale formattare valori invece di incollarli semplicemente, si ricorre all'API in stile printf che Java ha mutuato dal C.
Esistono tre punti di accesso strettamente correlati che si trovano regolarmente nel codice reale:
String.format(fmt, args...)— restituisce unaStringformattata."...".formatted(args...)— forma istanza aggiunta in Java 15. Risultato identico, più comoda per il chaining.System.out.printf(fmt, args...)— stampa direttamente su unPrintStream(o qualsiasiFormatter).
Tutti e tre condividono la stessa sintassi degli specificatori di formato. Imparala una volta sola.
Specificatori di formato
Uno specificatore ha la forma %[flags][width][.precision]conversion. La lettera di conversione è l'unico elemento obbligatorio. Il resto regola larghezza, allineamento, padding e precisione.
String s = String.format("%-10s | %5d | %8.2f", "apples", 42, 3.14159);
// "apples | 42 | 3.14"Le conversioni più utili:
| Conversione | Argomento | Significato |
|---|---|---|
%s | qualsiasi | toString() del valore |
%d | intero | intero decimale |
%f | virgola mobile | decimale a virgola fissa |
%e | virgola mobile | notazione scientifica |
%g | virgola mobile | il più breve tra %e e %f |
%x, %o | intero | esadecimale / ottale |
%c | carattere | singolo carattere |
%b | qualsiasi | true/false (null → "false") |
%n | nessuno | separatore di riga della piattaforma |
%% | nessuno | un % letterale |
%t... | data/ora | un'intera famiglia — %tF, %tT, ecc. |
La larghezza espande l'output ad almeno N caratteri; la precisione significa "cifre decimali" per i float e "caratteri massimi" per le stringhe.
Flag: allineamento, segno, zero-padding, raggruppamento
Alcuni flag si inseriscono tra % e la larghezza:
-— allineamento a sinistra nella larghezza. Il default è a destra.0— riempie con zeri fino alla larghezza (solo conversioni numeriche).+— mostra sempre il segno sui numeri (+42,-7).(spazio) — mostra uno spazio iniziale per i numeri positivi, come+ma con uno spazio.,— raggruppa le cifre usando il separatore delle migliaia della locale.(— racchiude i numeri negativi tra parentesi, stile contabilità.
String.format("%08d", 42); // "00000042"
String.format("%,d", 1234567); // "1,234,567"
String.format("%+.2f", 3.14159); // "+3.14"
String.format("%-10s|", "hi"); // "hi |"Larghezza e precisione
La larghezza è la larghezza minima del campo — se il valore formattato è più largo, nulla viene troncato.
La precisione ha significati diversi a seconda della conversione:
%.3f— tre cifre dopo la virgola decimale.%.10s— tronca la stringa a un massimo di 10 caratteri.%.4e— quattro cifre di precisione della mantissa.
Combinare larghezza e precisione è comune quando si vuole che le colonne siano allineate e i numeri arrotondati:
String.format("%10.4f", Math.PI); // " 3.1416"
String.format("%-10.4s", "abcdef"); // "abcd "%n vs \n
%n emette il separatore di riga appropriato alla piattaforma: "\n" su Unix, "\r\n" su Windows. \n è sempre esattamente un byte. Per file e output di protocollo in cui il terminatore di riga è importante con precisione, preferire \n e sceglierlo consapevolmente. Per l'output su console che deve apparire correttamente su qualunque OS stia girando la JVM, %n è la scelta più sicura.
Indici degli argomenti: riuso e riordinamento
Uno specificatore della forma %N$... fa riferimento all'N-esimo argomento (a base 1). Utile quando un valore appare più di una volta in un template, o quando l'ordine di lettura naturale differisce dall'ordine degli argomenti:
String.format("%1$s, %1$s, %1$s!", "go"); // "go, go, go!"
String.format("%2$s before %1$s", "lunch", "tea"); // "tea before lunch"Questo è lo strumento giusto quando si localizzano i template — lingue diverse posizionano i sostantivi in posizioni diverse, e un traduttore può riorganizzare i segnaposto senza toccare il sito di chiamata.
La locale è importante per numeri e date
La formattazione dei numeri rispetta la locale predefinita della JVM a meno che non venga sovrascritta. In en-US si ottiene 3.14; in de-DE si ottiene 3,14; in fr-FR le migliaia sono raggruppate con uno spazio non interrompibile. Per l'output destinato agli utenti, di solito è ciò che si vuole. Per i formati di dati — JSON, CSV, file di log, qualsiasi cosa leggibile da macchina — è un disastro che aspetta un deployment a Francoforte.
Passare sempre una locale esplicitamente per l'output leggibile da macchina:
String json = String.format(Locale.ROOT, "{\"price\": %.2f}", 19.95);
// "{\"price\": 19.95}" — always, regardless of JVM localeLocale.ROOT significa "nessuna formattazione specifica della locale" — punto come decimale, nessun raggruppamento. Locale.US è l'altra scelta comune per lo stesso scopo. La cosa pericolosa è non passare una locale e fare supposizioni.
Formattazione di data/ora
%t è una meta-conversione: la lettera che la segue sceglie il campo. Lo stesso argomento Date, Calendar, Long (millis) o java.time.temporal.TemporalAccessor può essere formattato in molti modi:
LocalDateTime now = LocalDateTime.of(2026, 5, 29, 14, 30, 15);
String.format("%tF", now); // "2026-05-29" — ISO date
String.format("%tT", now); // "14:30:15" — 24-hour time
String.format("%tA", now); // "Friday" — locale-dependent
String.format("%1$tF %1$tT", now); // "2026-05-29 14:30:15"Per qualsiasi cosa oltre la formattazione rapida, l'API java.time.format.DateTimeFormatter è più flessibile e consapevole della locale — ma %tF e simili rimangono comodi nelle righe di log.
Errori comuni
- Conversione sbagliata per il tipo.
String.format("%d", 3.14)lanciaIllegalFormatConversionExceptiona runtime —%drichiede un intero,%frichiede un numero in virgola mobile. Il compilatore non può verificarlo. - Argomenti mancanti. Dimenticare un argomento segnaposto lancia
MissingFormatArgumentException. - Decimale dipendente dalla locale nell'output della macchina. Trattato sopra.
%ssunull. Produce"null". Va bene per i log, imbarazzante nell'output rivolto agli utenti.- Usare
+per i numeri formattati."Price: " + 19.95dà"Price: 19.95", ma"Price: " + 0.1 + 0.2dà"Price: 0.10.2", non"Price: 0.3"— è concatenazione, non addizione.
Un esempio pratico
Un piccolo formattatore di riepilogo ordine che esercita larghezza, precisione, allineamento, raggruppamento, locale e conversione di date con %t. L'output è un report ordinato a due colonne — il tipo di cosa che altrimenti si costruirebbe a mano con helper padLeft.
Due cose da notare: il %<tT nella riga "Placed" riutilizza l'argomento precedente (< è il flag di riferimento all'indietro), evitando un secondo placedAt ridondante. E la riga JSON usa Locale.ROOT — lo stesso codice su una JVM tedesca emette comunque 1339.43, non 1339,43, che è esattamente ciò che un parser JSON si aspetta.
Cosa c'è dopo
Costruire le stringhe è una metà del lavoro. Confrontarle — uguaglianza, ordinamento, trasformazione del case, la differenza tra == e equals — è l'altra metà e una fonte frequente di bug sottili. Continua con Confronto di stringhe Java.