Saltar al contenido principal

List y ArrayList

Un array funciona bien cuando su tamaño está decidido. Si una agenda crece y mengua durante la ejecución, necesitamos una secuencia dinámica.

import java.util.ArrayList;
import java.util.List;

List<String> tareas = new ArrayList<>();

List es la interfaz y ArrayList la implementación. Conserva el orden de inserción, permite duplicados y usa índices desde cero.

Operaciones esenciales​

tareas.add("Estudiar");
tareas.add("Practicar");
tareas.add(1, "Descansar");

System.out.println(tareas.get(0));
tareas.set(1, "Pasear");
System.out.println(tareas.contains("Practicar"));
System.out.println(tareas.indexOf("Practicar"));
System.out.println(tareas.size());
  • add añade; con índice inserta y desplaza los siguientes.
  • get consulta y set reemplaza.
  • contains e indexOf buscan mediante igualdad.
  • size() devuelve el número de elementos e isEmpty() indica si está vacía.
  • clear() elimina todo; úsalo solo cuando esa sea realmente la intención.

Un índice fuera de 0 a size() - 1 provoca IndexOutOfBoundsException.

Recorrer una lista​

Si necesitas el índice:

for (int i = 0; i < tareas.size(); i++) {
System.out.println(i + ": " + tareas.get(i));
}

Si solo necesitas cada valor:

for (String tarea : tareas) {
System.out.println(tarea);
}

No añadas ni elimines elementos estructuralmente dentro de un foreach: el recorrido puede fallar. Más adelante veremos operaciones preparadas para eliminar por condición.

Eliminar por índice o por valor​

Con cadenas resulta claro:

tareas.remove(0);          // índice
tareas.remove("Practicar"); // valor

Con List<Integer> existe una ambigüedad importante:

List<Integer> numeros = new ArrayList<>(List.of(1, 2, 3, 2));
numeros.remove(2); // elimina el índice 2: el valor 3
numeros.remove(Integer.valueOf(2)); // elimina la primera aparición del valor 2

El compilador elige remove(int index) cuando recibe un int. Integer.valueOf(2) selecciona remove(Object value) de forma inequívoca.

Array frente a List​

ArrayList
Tamaño fijoTamaño dinámico
array.lengthlista.size()
Puede contener primitivasUsa wrappers para valores primitivos
Acceso con array[i]Acceso con lista.get(i)

Elige un array si la capacidad fija forma parte del problema. Elige List si importa el orden y la cantidad cambia. LinkedList es otra implementación, pero no la necesitamos para aprender el contrato de List.

Ejemplo completo​

import java.util.ArrayList;
import java.util.List;

public class ListaDemo {
public static void main(String[] args) {
List<String> compras = new ArrayList<>();
compras.add("pan");
compras.add("leche");
compras.add("pan");
compras.set(1, "avena");

for (int i = 0; i < compras.size(); i++) {
System.out.println(i + ": " + compras.get(i));
}

System.out.println("Eliminado: " + compras.remove("pan"));
System.out.println("Quedan: " + compras.size());
}
}

Errores habituales​

  • Usar i <= lista.size() en un recorrido.
  • Confundir length con size().
  • Confundir índice y valor al eliminar enteros.
  • Modificar la estructura durante un foreach.
  • Creer que se guardan primitivas sin autoboxing.

Practica: cola de reproducción​

Enunciado y criterios​

Crea una lista ordenada de canciones, permite duplicados, reemplaza la segunda, elimina una por valor y muestra posición y título. Comprueba también isEmpty().

Solución​

import java.util.ArrayList;
import java.util.List;

public class ReproduccionDemo {
public static void main(String[] args) {
List<String> canciones = new ArrayList<>();
canciones.add("Norte");
canciones.add("Sur");
canciones.add("Norte");
canciones.set(1, "Este");
canciones.remove("Norte");

for (int i = 0; i < canciones.size(); i++) {
System.out.println(i + " - " + canciones.get(i));
}
System.out.println("Vacía: " + canciones.isEmpty());
}
}

La lista conserva la secuencia y el duplicado restante. En JV3-03 veremos estructuras que expresan unicidad y asociaciones por clave.