Cómo imprimir un array en Java
Imprime arrays de Java de forma legible con Arrays.toString, Arrays.deepToString y formateo basado en streams.
Pasar un array directamente a System.out.println casi nunca imprime lo que quieres — obtienes algo como [I@1b6d3586 en lugar de los elementos. Los arrays no sobreescriben toString(), por lo que la versión predeterminada de Object imprime el tipo y un hash de identidad. Este capítulo muestra las soluciones idiomáticas: Arrays.toString para arrays planos, Arrays.deepToString para anidados, String.join para delimitadores personalizados, y un bucle manual cuando necesitas control total.
Por qué falla una impresión simple
El toString() predeterminado que un array hereda de Object devuelve una firma de clase más un código hash — no el contenido:
int[] numbers = {3, 1, 4};
System.out.println(numbers); // [I@1b6d3586
System.out.println("" + numbers); // same reference string[I significa "array de int"; el hexadecimal después de @ es el hash de identidad, que cambia entre ejecuciones. Concatenar el array en una cadena no ayuda, porque la concatenación también llama a toString(). La solución es pedirle a un método auxiliar que formatee los elementos por ti.
Arrays.toString para una dimensión
java.util.Arrays.toString recorre un array unidimensional y devuelve una cadena legible y separada por comas entre corchetes:
int[] numbers = {3, 1, 4, 1, 5};
System.out.println(Arrays.toString(numbers)); // [3, 1, 4, 1, 5]
String[] words = {"alpha", "beta"};
System.out.println(Arrays.toString(words)); // [alpha, beta]Está sobrecargado para cada tipo de array primitivo (int[], double[], boolean[], …) y para Object[], por lo que funciona con cualquier array plano que le pases. Para arrays de objetos, llama al propio toString() de cada elemento.
Arrays.deepToString para arrays anidados
Arrays.toString solo profundiza un nivel. En un array 2D formatea el array externo pero imprime cada array interno como una referencia. Usa Arrays.deepToString para recorrer todos los niveles de forma recursiva:
int[][] grid = {{1, 2}, {3, 4}};
System.out.println(Arrays.toString(grid)); // [[I@..., [I@...]
System.out.println(Arrays.deepToString(grid)); // [[1, 2], [3, 4]]Recurre a deepToString siempre que el array contenga otros arrays — matrices, arrays irregulares, arrays de arrays de objetos.
| Enfoque | Mejor para | Estilo de salida |
|---|---|---|
Arrays.toString | Arrays primitivos u de objetos 1D | [a, b, c] |
Arrays.deepToString | Arrays anidados / multidimensionales | [[a, b], [c, d]] |
String.join | String[] con un delimitador personalizado | a, b, c (sin corchetes) |
bucle manual / StringBuilder | control total sobre el formato | lo que construyas |
Formato personalizado
Cuando el formato con corchetes predeterminado no es el que quieres, String.join une un String[] (o cualquier iterable CharSequence) con el delimitador que elijas y sin corchetes circundantes:
String[] words = {"alpha", "beta", "gamma"};
System.out.println(String.join(" | ", words)); // alpha | beta | gammaPara arrays que no son de cadenas o para salida completamente personalizada, un bucle con StringBuilder te da control total sobre separadores, prefijos y el formato por elemento. Los streams son otra opción: Arrays.stream(arr).mapToObj(String::valueOf).collect(Collectors.joining(", ")).
Un ejemplo ejecutable
El programa a continuación contrasta los enfoques: Arrays.toString en int[] y String[] planos, la diferencia superficial vs. profunda en un array 2D, String.join para un delimitador personalizado, y un StringBuilder construido a mano. La línea shallow comprueba si el toString superficial del array 2D todavía contiene referencias internas, por lo que imprime un true estable en lugar de un hash que varía entre ejecuciones.
Lo que extraer de la ejecución:
toString: [3, 1, 4, 1, 5]muestra cómoArrays.toStringconvierte unint[]plano en texto legible con corchetes.words: [alpha, beta, gamma]confirma que el mismo método funciona en arrays de objetos llamando altoString()de cada elemento.shallow: truedemuestra queArrays.toStringsobre un array 2D deja los arrays internos como referencias[[I@..., por eso el resultado empieza con[[I@.deep: [[1, 2], [3, 4]]muestra cómoArrays.deepToStringrecursa en los arrays anidados para imprimir cada elemento.joined: alpha | beta | gammaymanual: {3; 1; 4; 1; 5}muestran cómoString.joiny un bucle conStringBuilderproducen salida sin corchetes y con delimitadores personalizados.