W3docs

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 una String formattata.
  • "...".formatted(args...) — forma istanza aggiunta in Java 15. Risultato identico, più comoda per il chaining.
  • System.out.printf(fmt, args...) — stampa direttamente su un PrintStream (o qualsiasi Formatter).

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:

ConversioneArgomentoSignificato
%squalsiasitoString() del valore
%dinterointero decimale
%fvirgola mobiledecimale a virgola fissa
%evirgola mobilenotazione scientifica
%gvirgola mobileil più breve tra %e e %f
%x, %ointeroesadecimale / ottale
%ccaratteresingolo carattere
%bqualsiasitrue/false (null → "false")
%nnessunoseparatore di riga della piattaforma
%%nessunoun % letterale
%t...data/oraun'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 locale

Locale.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) lancia IllegalFormatConversionException a runtime — %d richiede un intero, %f richiede 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.
  • %s su null. Produce "null". Va bene per i log, imbarazzante nell'output rivolto agli utenti.
  • Usare + per i numeri formattati. "Price: " + 19.95"Price: 19.95", ma "Price: " + 0.1 + 0.2"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.

java— editable, runs on the server

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.

Esercitazione

Pratica
Vuoi formattare un totale `double` come stringa con separatore delle migliaia ed esattamente due cifre decimali, e hai bisogno che il risultato usi il punto come separatore decimale indipendentemente dalla locale della JVM (in modo che un consumer JSON possa analizzarlo). Quale chiamata lo fa correttamente?
Vuoi formattare un totale `double` come stringa con separatore delle migliaia ed esattamente due cifre decimali, e hai bisogno che il risultato usi il punto come separatore decimale indipendentemente dalla locale della JVM (in modo che un consumer JSON possa analizzarlo). Quale chiamata lo fa correttamente?
Was this page helpful?