Saltar al contenido
arrays.java · devschool

Arrays en Java

Lección 11 de 26 · 13 min de lectura · Actualizado el

En esta lección
  1. Por qué existen los arrays
  2. Declarar y crear un array
  3. Acceder a los elementos y length
  4. Recorrer un array
  5. Operaciones típicas
  6. La clase Arrays
  7. Copiar arrays: referencia frente a copia
  8. Arrays de objetos
  9. Más allá de los arrays
  10. Errores frecuentes
  11. Resumen

Un array guarda varios valores del mismo tipo bajo un único nombre, uno detrás de otro, y con un tamaño fijo. Es la estructura de datos más básica de Java y la base de muchas otras. En esta lección aprenderás a crear arrays, a leerlos y recorrerlos, a calcular máximos, mínimos y medias, a usar la clase Arrays para ordenar, copiar y comparar, y a evitar los errores típicos, sobre todo el de copiar un array “sin copiarlo”.

Por qué existen los arrays

Imagina que quieres guardar las temperaturas máximas de una semana. Con lo que sabes de variables, necesitarías siete:

int lunes = 18, martes = 21, miercoles = 25, jueves = 23;
int viernes = 19, sabado = 16, domingo = 14;

Ahora calcula la media, o busca el día más caluroso. Tienes que escribir cada variable a mano, y si fueran las 365 temperaturas del año sería imposible. Con un array guardas todas en una sola variable y las recorres con un bucle:

int[] temperaturas = {18, 21, 25, 23, 19, 16, 14};

Cada valor ocupa una posición (o índice) numerada desde 0:

índice:        0    1    2    3    4    5    6
temperaturas: 18   21   25   23   19   16   14

Declarar y crear un array

Un array se declara poniendo [] detrás del tipo:

int[] notas;          // un array de enteros, todavía sin crear
String[] nombres;     // un array de textos

Java también admite int notas[], heredado del lenguaje C, pero la forma habitual es int[] notas: así el tipo completo (int[], “array de int”) queda junto.

Declarar no crea el array. Hay dos formas de crearlo.

Con new y un tamaño

int[] notas = new int[5];          // 5 posiciones
double[] precios = new double[3];  // 3 posiciones

El tamaño puede ser cualquier expresión entera, también una variable que se conoce al ejecutar el programa:

int alumnos = 4;                   // podría venir de un Scanner
int[] notas = new int[alumnos];

Pero una vez creado, el tamaño ya no cambia. Si necesitas una lista que crezca, usa un ArrayList, que verás en ArrayList y listas.

Con valores iniciales

Si ya conoces los valores, escríbelos entre llaves. Java cuenta cuántos hay y crea el array de ese tamaño:

int[] temperaturas = {18, 21, 25, 23, 19, 16, 14};
String[] dias = {"lunes", "martes", "miércoles", "jueves", "viernes", "sábado", "domingo"};

Las llaves a secas solo se pueden usar en la misma línea de la declaración. En cualquier otro sitio, por ejemplo al pasar un array a un método o al reasignar una variable, hay que escribir new int[] delante:

temperaturas = new int[] {20, 22, 24};   // correcto
// temperaturas = {20, 22, 24};          // no compila

Valores por defecto

Cuando creas un array con new, Java rellena todas las posiciones con un valor por defecto que depende del tipo:

TipoValor por defecto
int, long, short, byte0
double, float0.0
booleanfalse
charel carácter de código 0 ('\u0000'), que no se ve
String y cualquier objetonull
System.out.println(Arrays.toString(new int[5]));      // [0, 0, 0, 0, 0]
System.out.println(Arrays.toString(new boolean[2]));  // [false, false]
System.out.println(Arrays.toString(new String[3]));   // [null, null, null]

Acceder a los elementos y length

Cada elemento se lee o se cambia con el nombre del array y el índice entre corchetes:

int[] temperaturas = {18, 21, 25, 23, 19, 16, 14};

System.out.println(temperaturas[0]);  // 18 (el primero)
System.out.println(temperaturas[6]);  // 14 (el último)
temperaturas[2] = 26;                 // el miércoles fueron 26 grados

La propiedad length indica cuántos elementos tiene. Se escribe sin paréntesis, a diferencia del método length() de los String:

System.out.println(temperaturas.length);                          // 7
System.out.println(temperaturas[temperaturas.length - 1]);        // 14

Como los índices empiezan en 0, el último elemento siempre está en length - 1. Usar length en vez de escribir el número a mano hace que el código siga funcionando si el array cambia de tamaño.

ArrayIndexOutOfBoundsException

Si usas un índice que no existe, el programa compila, pero al ejecutarse se detiene con una excepción:

System.out.println(temperaturas[7]);
// ArrayIndexOutOfBoundsException: Index 7 out of bounds for length 7

System.out.println(temperaturas[-1]);
// ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 7

El mensaje dice qué índice pediste y cuál es la longitud. Los índices válidos van de 0 a length - 1, así que un array de 7 elementos no tiene posición 7. Es el error más típico con arrays, casi siempre por escribir <= en lugar de < en un bucle. Aprenderás a capturar excepciones en excepciones, pero lo correcto aquí es no provocarla.

Recorrer un array

Con for clásico

Cuando necesitas la posición, por ejemplo para relacionar dos arrays o para modificar elementos:

for (int i = 0; i < temperaturas.length; i++) {
    System.out.println(dias[i] + ": " + temperaturas[i] + " ºC");
}
lunes: 18 ºC
martes: 21 ºC
miércoles: 26 ºC
jueves: 23 ºC
viernes: 19 ºC
sábado: 16 ºC
domingo: 14 ºC

Con for-each

Cuando solo necesitas leer cada valor, el for-each es más corto y no puede salirse de rango:

int suma = 0;
for (int t : temperaturas) {
    suma += t;
}

Se lee “para cada t de temperaturas”. Pero ojo: la variable del for-each es una copia del valor. Cambiarla no cambia el array:

int[] puntos = {5, 3, 8};

for (int p : puntos) {
    p = p * 2;                        // solo cambia la copia
}
System.out.println(Arrays.toString(puntos)); // [5, 3, 8]

for (int i = 0; i < puntos.length; i++) {
    puntos[i] = puntos[i] * 2;        // cambia el array de verdad
}
System.out.println(Arrays.toString(puntos)); // [10, 6, 16]

Operaciones típicas

Estos patrones aparecen en casi todos los ejercicios. Merece la pena saberlos escribir sin mirar.

Suma y media

int suma = 0;
for (int t : temperaturas) {
    suma += t;
}
double media = (double) suma / temperaturas.length;
System.out.printf("Media: %.2f%n", media);   // Media: 19.57

El (double) evita la división entera, que daría 19.

Máximo y mínimo

La idea: supón que el primero es el mayor y compáralo con el resto. No empieces en 0 como valor inicial: si todas las temperaturas fueran negativas, el máximo saldría 0.

int max = temperaturas[0];
int min = temperaturas[0];
int posMax = 0;

for (int i = 1; i < temperaturas.length; i++) {
    if (temperaturas[i] > max) {
        max = temperaturas[i];
        posMax = i;                      // recuerda dónde estaba
    }
    if (temperaturas[i] < min) {
        min = temperaturas[i];
    }
}
System.out.println(max + " " + min);               // 26 14
System.out.println("Día más caluroso: " + dias[posMax]); // Día más caluroso: miércoles

Contar y buscar

int calurosos = 0;
for (int t : temperaturas) {
    if (t >= 20) {
        calurosos++;
    }
}
System.out.println(calurosos); // 3

int posicion = -1;                       // -1 significa "no encontrado"
for (int i = 0; i < dias.length; i++) {
    if (dias[i].equals("jueves")) {
        posicion = i;
        break;                           // ya lo tenemos, no seguimos
    }
}
System.out.println(posicion); // 3

Para comparar String usa siempre equals, nunca == (lo viste en String y StringBuilder).

La clase Arrays

El paquete java.util incluye la clase Arrays, con métodos ya hechos para las tareas más comunes. Necesitas importarla al principio del archivo:

import java.util.Arrays;

toString: mostrar el contenido

Si imprimes un array directamente, no ves sus valores, sino el tipo y un código ([I significa “array de int”):

int[] edades = {34, 19, 52, 27, 19};
System.out.println(edades);                  // [I@5f683daf
System.out.println(Arrays.toString(edades)); // [34, 19, 52, 27, 19]

sort: ordenar

Ordena el array en el sitio, es decir, modifica el original de menor a mayor:

Arrays.sort(edades);
System.out.println(Arrays.toString(edades)); // [19, 19, 27, 34, 52]

String[] socios = {"Pablo", "ana", "Lucía", "Beatriz"};
Arrays.sort(socios);
System.out.println(Arrays.toString(socios)); // [Beatriz, Lucía, Pablo, ana]

Los textos se ordenan por el código de cada carácter, y las mayúsculas van antes que las minúsculas: por eso ana queda la última. Para otros órdenes se usa un Comparator, que verás en ArrayList y listas.

fill: rellenar

int[] marcador = new int[4];
Arrays.fill(marcador, -1);
System.out.println(Arrays.toString(marcador)); // [-1, -1, -1, -1]

copyOf y copyOfRange: copiar

copyOf crea un array nuevo con la longitud que indiques. Si es mayor, rellena con valores por defecto; si es menor, recorta:

int[] original = {1, 2, 3};
System.out.println(Arrays.toString(Arrays.copyOf(original, 5))); // [1, 2, 3, 0, 0]
System.out.println(Arrays.toString(Arrays.copyOf(original, 2))); // [1, 2]

int[] trozo = Arrays.copyOfRange(new int[] {10, 20, 30, 40, 50}, 1, 4);
System.out.println(Arrays.toString(trozo)); // [20, 30, 40] (del 1 al 4, sin incluir el 4)

Es la forma de “hacer crecer” un array: crear uno más grande y reasignar la variable. Si lo haces a menudo, necesitas un ArrayList.

equals: comparar contenido

== compara si dos variables apuntan al mismo array, no si tienen los mismos valores:

int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
System.out.println(a == b);              // false: son dos arrays distintos
System.out.println(Arrays.equals(a, b)); // true: mismo contenido

binarySearch: buscar en un array ordenado

La búsqueda binaria es muy rápida: mira el centro, descarta la mitad donde no puede estar el valor y repite. Por eso solo funciona si el array está ordenado. Devuelve la posición, o un número negativo si no lo encuentra:

int[] ordenado = {3, 8, 15, 22, 40};
System.out.println(Arrays.binarySearch(ordenado, 22)); // 3
System.out.println(Arrays.binarySearch(ordenado, 10)); // -3 (no está)

System.out.println(Arrays.binarySearch(new int[] {40, 3, 22, 8}, 40)); // -5: ¡mal!

En el último caso el 40 está en la posición 0, pero como el array no está ordenado, el resultado no tiene sentido. Ordena antes con Arrays.sort o usa un bucle normal.

Copiar arrays: referencia frente a copia

Esta es la trampa más importante de la lección. Una variable de tipo array no guarda los valores, sino la dirección donde está el array en memoria (lo viste en variables). Por eso, al asignar un array a otra variable no se copia nada: las dos variables apuntan al mismo array.

int[] precios = {10, 20, 30};
int[] otro = precios;        // NO es una copia: es otro nombre para el mismo array
otro[0] = 99;
System.out.println(Arrays.toString(precios)); // [99, 20, 30]
precios ──┐
          ├──> [99, 20, 30]
otro ─────┘

Para tener una copia independiente, crea un array nuevo. Hay tres formas equivalentes:

int[] precios = {10, 20, 30};

int[] copia1 = precios.clone();
int[] copia2 = Arrays.copyOf(precios, precios.length);

int[] copia3 = new int[precios.length];
System.arraycopy(precios, 0, copia3, 0, precios.length); // origen, posición de origen, destino, posición de destino, cuántos

copia1[0] = 99;
System.out.println(Arrays.toString(precios)); // [10, 20, 30]: el original no cambia
System.out.println(Arrays.toString(copia1));  // [99, 20, 30]

System.arraycopy permite además copiar un trozo en cualquier posición del destino.

Al pasar un array a un método ocurre lo mismo que al asignarlo: el método recibe la dirección, así que puede modificar el contenido del original. Lo tienes explicado con detalle en métodos.

Arrays de objetos

Un array puede guardar cualquier tipo, también String o objetos de tus propias clases. En ese caso, cada posición guarda una referencia a un objeto, y hasta que no la rellenas vale null:

String[] equipo = new String[3];
equipo[0] = "Irene";
System.out.println(Arrays.toString(equipo)); // [Irene, null, null]

System.out.println(equipo[1].length());      // NullPointerException

Llamar a un método sobre null lanza NullPointerException: no hay ningún objeto al que preguntarle su longitud. Antes de usar una posición, asegúrate de que la has rellenado.

Con tus propias clases funciona igual. Este carrito guarda objetos Producto (las clases se explican en la lección de clases y objetos):

public class Tienda {
    public static void main(String[] args) {
        Producto[] carrito = new Producto[3];
        carrito[0] = new Producto("Teclado", 24.99);
        carrito[1] = new Producto("Ratón", 12.50);
        carrito[2] = new Producto("Alfombrilla", 6.00);

        double total = 0;
        for (Producto p : carrito) {
            System.out.println(p.nombre + ": " + p.precio + " €");
            total += p.precio;
        }
        System.out.printf("Total: %.2f €%n", total);
    }
}

class Producto {
    String nombre;
    double precio;

    Producto(String nombre, double precio) {
        this.nombre = nombre;
        this.precio = precio;
    }
}
Teclado: 24.99 €
Ratón: 12.5 €
Alfombrilla: 6.0 €
Total: 43.49 €

Más allá de los arrays

Para datos en forma de tabla (notas por alumno y asignatura, un tablero de juego) se usan arrays de arrays: las matrices. Y si no sabes cuántos elementos tendrás, usa un ArrayList, que crece solo: lo tienes en ArrayList y listas.

Errores frecuentes

  • Salirse del array: i <= array.length en el bucle. La condición correcta es i < array.length.
  • Escribir length() con paréntesis. En arrays es length; en String, length(); en listas, size().
  • Imprimir el array con println: sale [I@.... Usa Arrays.toString.
  • Comparar arrays con ==: usa Arrays.equals.
  • Creer que b = a copia el array: solo copia la dirección. Usa clone() o Arrays.copyOf.
  • Modificar con for-each: la variable del bucle es una copia.
  • Usar binarySearch sin ordenar antes.
  • Iniciar el máximo en 0: empieza por el primer elemento del array.
  • Olvidar import java.util.Arrays;: cannot find symbol.

Resumen

TareaCódigo
Crear con tamañoint[] a = new int[5];
Crear con valoresint[] a = {4, 8, 15};
Leer / cambiara[0], a[0] = 7;
Longituda.length
Último elementoa[a.length - 1]
Recorrerfor (int i = 0; i < a.length; i++) o for (int x : a)
MostrarArrays.toString(a)
OrdenarArrays.sort(a)
RellenarArrays.fill(a, valor)
Copiara.clone(), Arrays.copyOf(a, n), System.arraycopy
Comparar contenidoArrays.equals(a, b)
Buscar (ordenado)Arrays.binarySearch(a, valor)

Los arrays tienen tamaño fijo, índices desde 0 y guardan referencias cuando contienen objetos. Con eso claro, el siguiente paso son las matrices, y después, las clases y objetos.

Pon a prueba lo que has aprendido

[Java] ¿Qué muestra este código?
int[] notas = {7, 9, 5};
System.out.println(notas.length);

[Java] ¿Qué pasa con este código?
int[] numeros = new int[3];
numeros[3] = 10;

[Java] ¿Qué imprime este código?
int[] a = {1, 2, 3};
int[] b = a;
b[1] = 20;
System.out.println(a[1]);

[Java] Este código busca la temperatura más alta. ¿Qué imprime?
int[] t = {-5, -2, -9};
int max = 0;
for (int x : t) {
    if (x > max) max = x;
}
System.out.println(max);

¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.