W3docs

Conversioni di String in Java

Converti tra stringhe Java e primitivi — Integer.parseInt, Double.parseDouble, String.valueOf e altro ancora.

La maggior parte dei dati arriva come testo e la maggior parte dei dati parte come testo. Tra questi due confini, di solito vive come qualcosa di più utile — un int, un double, un boolean, un LocalDate. Questo capitolo riguarda le due direzioni di conversione tra String e i tipi primitivi, i tipi wrapper e gli array di caratteri.

Esiste un piccolo vocabolario che vale la pena memorizzare; una volta conosciuto, la risposta alla domanda "come trasformo questa stringa in una X" è sempre una riga singola.

String → primitivo: la famiglia parse...

Ogni classe wrapper ha un metodo statico che accetta una String e restituisce il primitivo corrispondente:

int    i = Integer.parseInt("42");
long   l = Long.parseLong("9999999999");
double d = Double.parseDouble("3.14");
float  f = Float.parseFloat("3.14");
short  s = Short.parseShort("32000");
byte   b = Byte.parseByte("127");
boolean ok = Boolean.parseBoolean("true");  // any case-insensitive "true"; everything else → false

Questi sono gli strumenti standard. Lanciano NumberFormatException per input che non viene analizzato — inclusi null, stringhe vuote, stringhe con spazi, decimali specifici per la locale come "3,14" e valori fuori intervallo.

Integer.parseInt(" 42 ");      // NumberFormatException — trim first
Integer.parseInt("3.0");       // NumberFormatException — that's a double
Integer.parseInt("1234567890123"); // NumberFormatException — overflows int

Integer.parseInt accetta un secondo argomento opzionale per la base:

Integer.parseInt("ff", 16);    // 255
Integer.parseInt("1010", 2);   // 10
Integer.parseInt("777", 8);    // 511 — the radix is the second arg, not a prefix
Integer.parseInt("0x1A", 16);  // NumberFormatException — no "0x" prefix; pass just "1A"

parseInt legge le cifre letterali nella base che passi; non comprende i prefissi del codice sorgente come 0x o uno 0 iniziale per l'ottale. Quindi Integer.parseInt("0777", 8) va bene — lo 0 iniziale è semplicemente un'altra cifra ottale — ma Integer.parseInt("0x1A", 16) lancia un'eccezione, perché x non è una cifra in base 16. Rimuovi qualsiasi prefisso tu stesso prima di fare il parsing.

Per l'interpretazione senza segno del bit alto su valori a 32 e 64 bit, il JDK aggiunge Integer.parseUnsignedInt e Long.parseUnsignedLong.

String → wrapper: valueOf vs parse...

Il metodo statico valueOf su ogni wrapper esegue lo stesso parsing ma restituisce il tipo wrapper:

Integer n = Integer.valueOf("42");     // Integer, not int
Double d  = Double.valueOf("3.14");    // Double, not double

I due differiscono in tre punti che occasionalmente contano:

  • Tipo restituito. parseIntint, valueOfInteger. Scegli quello che si adatta alla destinazione.
  • Cache. Integer.valueOf(int) e Long.valueOf(long) memorizzano nella cache i numeri piccoli (-128..127 per impostazione predefinita), restituendo la stessa istanza di Integer per chiamate ripetute. parseInt restituisce un primitivo, quindi la cache non è rilevante — ma quando si stava comunque inscatolando il risultato, valueOf è più economico.
  • Comportamento in caso di overflow. Identico — entrambi lanciano NumberFormatException.

Regola pratica: se vuoi un primitivo, usa parseInt; se vuoi un wrapper, usa valueOf. Non scrivere Integer.valueOf(Integer.parseInt(s)) — è il codice di due parsing per il risultato di uno.

Primitivo → String: String.valueOf e simili

La direzione inversa ha due strumenti ben nominati:

String s1 = String.valueOf(42);              // "42"
String s2 = String.valueOf(3.14);            // "3.14"
String s3 = String.valueOf(true);            // "true"
String s4 = String.valueOf('a');             // "a"
String s5 = String.valueOf(new char[]{'h','i'}); // "hi"
String s6 = String.valueOf((Object) null);   // "null"  — NOT an NPE

Ogni wrapper ha anche un toString che accetta il primitivo:

Integer.toString(42);          // "42"
Integer.toString(255, 16);     // "ff"   — radix overload
Long.toString(123456789L);     // "123456789"
Double.toString(3.14);         // "3.14"

E naturalmente, la concatenazione con "" funziona:

String s = "" + 42;            // "42"

String.valueOf è il più generale e lo stile più difendibile — non lancia mai su null e gestisce ogni primitivo più Object. Per la formattazione numerica in cui hai bisogno di larghezza, segno, raggruppamento o decimali specifici per la locale, usa invece String.format.

Stringhe e char

Un char è un primitivo (un'unità di codice UTF-16); una String è una sequenza di essi. Conversioni in entrambe le direzioni:

String  s   = String.valueOf('a');       // "a"
char    c1  = "abc".charAt(0);           // 'a'
char[]  arr = "abc".toCharArray();       // ['a', 'b', 'c']
String  s2  = new String(arr);           // "abc"
String  s3  = new String(arr, 1, 2);     // "bc" — offset + count

String.toCharArray() restituisce sempre un array fresco e modificabile. È lo strumento giusto quando hai bisogno di mutare i caratteri (ad esempio per cancellare un buffer password) — la String stessa non può darti una vista mutabile.

Stringhe e byte

I byte sono il formato di rete; le stringhe sono la forma in memoria. La conversione implica sempre un charset, e la risposta giusta è sempre passarlo esplicitamente:

byte[] bytes = "héllo".getBytes(StandardCharsets.UTF_8);
String back  = new String(bytes, StandardCharsets.UTF_8);

Le versioni senza argomenti (getBytes(), new String(bytes)) usano il charset predefinito della JVM, che dipende dalla piattaforma ed è una fonte costante di bug "funziona sulla mia macchina". Passa sempre un Charset. UTF-8 è il valore predefinito corretto per il nuovo codice; i sistemi legacy a volte hanno bisogno di Latin-1 o di una delle code page Windows.

Conversioni che non esistono

Alcune conversioni che le persone cercano e che non sono disponibili:

  • intchar per valore cifra. (char) 5 è il carattere di controllo al code point 5, non '5'. Usa Character.forDigit(5, 10) oppure (char) ('0' + 5).
  • charint per valore cifra. (int) '5' è 53, non 5. Usa Character.digit('5', 10) oppure '5' - '0'.
  • String → numerico con valore predefinito in caso di errore. Java non fornisce un parseIntOrDefault. La versione idiomatica è un piccolo helper:
static int parseIntOr(String s, int fallback) {
  try { return Integer.parseInt(s); }
  catch (NumberFormatException e) { return fallback; }
}

La conversione non è validazione

Il singolo errore più grande nella conversione da stringa a primitivo è trattare un parsing riuscito come una validazione riuscita. Integer.parseInt("0") restituisce 0 per qualsiasi input che l'utente digita come zero, inclusi "0", "00", "+0" e "-0" — tutti analizzano allo stesso valore. Se ti importa se l'input era canonico, esegui il parsing e poi riconverti:

int v = Integer.parseInt(input);
if (!Integer.toString(v).equals(input)) {
  throw new IllegalArgumentException("non-canonical integer: " + input);
}

Per gli input numerici provenienti da moduli rivolti all'utente, valida prima il formato (regex, lunghezza, caratteri consentiti), poi esegui il parsing. Non affidarti al parser per dirti se l'input era ragionevole.

Un esempio pratico

Un programma che converte in entrambe le direzioni tra i tipi più comuni, incluso un helper robusto con valore predefinito in caso di errore, un round-trip esadecimale e un round-trip byte/string con UTF-8.

java— editable, runs on the server

Tre dettagli da notare nell'output. La stringa héllo fa il round-trip attraverso UTF-8 correttamente — cinque caratteri diventano sei byte (la é occupa due), e i byte risultanti vengono analizzati di nuovo negli stessi cinque caratteri. String.valueOf((Object)null) produce "null" invece di lanciare — è deliberato; è per questo che "x = " + nullable non si blocca. E l'helper parseIntOr gestisce input errati, input con spazi e input null senza che il sito chiamante debba saperlo.

Cosa c'è dopo

Il capitolo che chiude la Parte 9 copre i due metodi "string in, list out / list in, string out" più utilizzati nella libreria standard — e le varianti con espressioni regolari che si trovano al di sotto. Continua con Java String split() e join().

Pratica

Pratica
Qual è la differenza tra `Integer.parseInt('42')` e `Integer.valueOf('42')`?
Qual è la differenza tra `Integer.parseInt('42')` e `Integer.valueOf('42')`?
Was this page helpful?