Conversiones de String en Java
Convierte entre strings y primitivos en Java — Integer.parseInt, Double.parseDouble, String.valueOf y más.
La mayoría de los datos llegan como texto y la mayoría de los datos salen como texto. Entre esos dos límites suelen vivir como algo más útil — un int, un double, un boolean, un LocalDate. Este capítulo trata sobre las dos direcciones de conversión entre String y los tipos primitivos, los tipos envolventes y los arrays de caracteres.
Hay un pequeño vocabulario que vale la pena memorizar; una vez que lo conoces, la respuesta a "¿cómo convierto este string en un X?" es siempre una sola línea.
String → primitivo: la familia parse...
Cada clase envolvente tiene un método estático que recibe un String y devuelve el primitivo correspondiente:
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 → falseEstas son las herramientas estándar. Lanzan NumberFormatException para entradas que no se pueden parsear — incluyendo null, strings vacíos, strings con espacios en blanco, decimales con formato regional como "3,14" y valores fuera de rango.
Integer.parseInt(" 42 "); // NumberFormatException — trim first
Integer.parseInt("3.0"); // NumberFormatException — that's a double
Integer.parseInt("1234567890123"); // NumberFormatException — overflows intInteger.parseInt acepta un segundo argumento opcional para 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 lee los dígitos literales en la base que se le pasa; no entiende los prefijos del código fuente como 0x ni un 0 inicial para octal. Por eso Integer.parseInt("0777", 8) está bien — el 0 inicial es simplemente otro dígito octal — pero Integer.parseInt("0x1A", 16) lanza una excepción, porque x no es un dígito en base 16. Elimina cualquier prefijo tú mismo antes de parsear.
Para interpretación sin signo del bit más significativo en valores de 32 y 64 bits, el JDK añade Integer.parseUnsignedInt y Long.parseUnsignedLong.
String → envolvente: valueOf vs parse...
El valueOf estático en cada clase envolvente hace el mismo parseo pero devuelve el tipo envolvente:
Integer n = Integer.valueOf("42"); // Integer, not int
Double d = Double.valueOf("3.14"); // Double, not doubleLos dos difieren en tres puntos que a veces importan:
- Tipo de retorno.
parseInt→int,valueOf→Integer. Elige el que necesite tu destinatario. - Caché.
Integer.valueOf(int)yLong.valueOf(long)almacenan en caché números pequeños (-128..127por defecto), devolviendo la misma instancia deIntegerpara llamadas repetidas.parseIntdevuelve un primitivo, por lo que el caché no aplica — pero cuando igual ibas a hacer boxing del resultado,valueOfes más económico. - Comportamiento en desbordamiento. Idéntico — ambos lanzan
NumberFormatException.
Regla general: si quieres un primitivo, usa parseInt; si quieres un envolvente, usa valueOf. No escribas Integer.valueOf(Integer.parseInt(s)) — eso son dos parseos de código para un solo parseo de resultado.
Primitivo → String: String.valueOf y similares
La dirección inversa tiene dos herramientas bien nombradas:
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 NPECada clase envolvente también tiene un toString que recibe el primitivo:
Integer.toString(42); // "42"
Integer.toString(255, 16); // "ff" — radix overload
Long.toString(123456789L); // "123456789"
Double.toString(3.14); // "3.14"Y por supuesto, la concatenación con "" también funciona:
String s = "" + 42; // "42"String.valueOf es el más general y el estilo más defendible — nunca lanza excepción con null y maneja todos los primitivos más Object. Para formateo numérico donde necesitas ancho, signo, agrupación o decimales con formato regional, recurre a String.format.
Strings y chars
Un char es un primitivo (una unidad de código UTF-16); un String es una secuencia de ellos. Conversiones en ambas direcciones:
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 + countString.toCharArray() siempre devuelve un array nuevo y modificable. Es la herramienta adecuada cuando necesitas mutar caracteres (por ejemplo, para limpiar un buffer de contraseña) — el propio String no puede darte una vista mutable.
Strings y bytes
Los bytes son el formato de red; los strings son la forma en memoria. La conversión siempre implica un charset, y la respuesta correcta es siempre pasarlo explícitamente:
byte[] bytes = "héllo".getBytes(StandardCharsets.UTF_8);
String back = new String(bytes, StandardCharsets.UTF_8);Las sobrecargas sin argumentos (getBytes(), new String(bytes)) usan el charset por defecto de la JVM, que depende de la plataforma y es una fuente constante de errores del tipo "funciona en mi máquina". Siempre pasa un Charset. UTF-8 es el valor por defecto correcto para código nuevo; los sistemas heredados a veces necesitan Latin-1 o una de las páginas de código Windows.
Conversiones que no existen
Algunas conversiones que la gente busca pero que no están disponibles:
int→charpor valor de dígito.(char) 5es el carácter de control en el punto de código 5, no'5'. UsaCharacter.forDigit(5, 10)o(char) ('0' + 5).char→intpor valor de dígito.(int) '5'es 53, no 5. UsaCharacter.digit('5', 10)o'5' - '0'.String→ numérico con valor por defecto en caso de error. Java no incluye unparseIntOrDefault. La versión idiomática es un pequeño helper:
static int parseIntOr(String s, int fallback) {
try { return Integer.parseInt(s); }
catch (NumberFormatException e) { return fallback; }
}La conversión no es validación
El mayor error con la conversión de string a primitivo es tratar un parseo exitoso como una validación exitosa. Integer.parseInt("0") devuelve 0 para cualquier entrada que el usuario escriba como cero, incluyendo "0", "00", "+0" y "-0" — todas las cuales parsean al mismo valor. Si te importa que la entrada sea canónica, parsea y luego convierte de vuelta:
int v = Integer.parseInt(input);
if (!Integer.toString(v).equals(input)) {
throw new IllegalArgumentException("non-canonical integer: " + input);
}Para entradas numéricas de formularios orientados al usuario, valida primero el formato (regex, longitud, caracteres permitidos) y luego parsea. No te apoyes en el parser para determinar si la entrada era razonable.
Un ejemplo completo
Un programa que convierte en ambas direcciones para los tipos más comunes, incluyendo un helper robusto con valor por defecto en caso de error, un viaje de ida y vuelta en hexadecimal y un viaje de ida y vuelta bytes/string con UTF-8.
Tres detalles a observar en la salida. El string héllo va y viene a través de UTF-8 sin problemas — cinco caracteres se convierten en seis bytes (la é ocupa dos), y los bytes resultantes se parsean de vuelta en los mismos cinco caracteres. String.valueOf((Object)null) produce "null" en lugar de lanzar una excepción — eso es deliberado; es por qué "x = " + nullable no explota. Y el helper parseIntOr maneja entradas incorrectas, entradas con espacios y entradas null sin que el sitio de llamada tenga que saberlo.
¿Qué sigue?
El capítulo que cierra la Parte 9 cubre los dos métodos más usados de "string de entrada, lista de salida / lista de entrada, string de salida" en la biblioteca estándar — y las variantes basadas en regex que subyacen a ellos. Continúa en Java String split() y join().