Listas
En resumen: Una lista es una colección que crece y se encoge sola; ArrayList guarda los elementos en orden como un array, y List<String> dice de qué tipo son.
Problema
El carrito está lleno
Estás escribiendo el carrito de compras de una tienda en línea, y guardas los productos en un array. Pero un array tiene un tamaño que no cambia. Cuando el cliente añade un cuarto producto, creas un array más grande y copias todo. Cuando quita un producto, queda un hueco:
String[] cart = { "Pan", "Leche", "Café" };
// Un cuarto producto: el array está lleno, así que creamos uno más grande y copiamos.String[] bigger = new String[cart.length + 1];for (int i = 0; i < cart.length; i++) { bigger[i] = cart[i];}bigger[cart.length] = "Mantequilla";cart = bigger;
// El cliente quita la leche.cart[1] = null;
for (String item : cart) { System.out.println(item);}PannullCaféMantequillanull. Y el número de productos ya no es cart.length.Es mucho código para algo que toda tienda hace todo el tiempo.
La idea
ArrayList: un array que se cuida solo
Java tiene una clase lista para esto: ArrayList. Guarda los elementos en un array, pero copia y desplaza sola. Una colección así se llama lista:
import java.util.ArrayList;
public class Main { public static void main(String[] args) { ArrayList<String> cart = new ArrayList<>(); cart.add("Pan"); cart.add("Leche"); cart.add("Café"); cart.add("Mantequilla"); cart.remove("Leche"); System.out.println(cart); System.out.println("Productos: " + cart.size()); }}[Pan, Café, Mantequilla]Productos: 3ArrayListestá en el paquetejava.util, así que el archivo empieza con unimport, como conScanner.addañade al final, yremovequita y cierra el hueco: «Café» pasa al lugar de «Leche».size()es cuántos elementos hay ahora mismo. No eslength, porque una lista no es un array.printlnimprime toda la lista entre corchetes.
Esto es lo que hace ArrayList por dentro. El número entre paréntesis es el tamaño inicial del array. Sin él, es 10. Aquí es 3, para que veas qué pasa cuando el array se llena:
ArrayList<String> cart = new ArrayList<>(3);cart.add("Pan");cart.add("Leche");cart.add("Café");cart.add("Mantequilla");cart.remove("Leche");System.out.println(cart);System.out.println("Productos: " + cart.size());Paso a paso, en palabras
- cart apunta a un objeto ArrayList. Dentro hay un array con 3 lugares y un contador size.
- add pone cada elemento en el primer lugar libre y aumenta size.
- El array está lleno. ArrayList crea uno nuevo con 4 lugares y copia en él los tres elementos.
- Ahora el objeto apunta al array nuevo, y el viejo ya no lo necesita nadie. «Mantequilla» va al lugar libre.
- remove quita «Leche», y todo lo que viene después se mueve un lugar a la izquierda. No queda ningún hueco.
- Desde fuera solo ves una lista de tres productos: ArrayList se encarga de copiar y de mover.
La idea
Qué va entre los corchetes angulares
ArrayList<String> significa «una lista de texto». El tipo entre los corchetes angulares se llama parámetro de tipo (generics). Le dice al compilador qué hay en la lista, y el compilador lo hace cumplir:
import java.util.ArrayList;
public class Main { public static void main(String[] args) { ArrayList<String> cart = new ArrayList<>(); cart.add("Pan"); cart.add(5); }}Main.java:7: error: incompatible types: int cannot be converted to String cart.add(5); ^Por eso cart.get(0) devuelve directamente un String, sin ninguna conversión.
A la derecha, los corchetes angulares están vacíos: new ArrayList<>(). El compilador toma el tipo del lado izquierdo.
Normalmente la variable se declara con la interfaz List, y la clase ArrayList solo aparece después de new:
List<String> cart = new ArrayList<>();cart.add("Pan");System.out.println(cart.get(0));Es el polimorfismo del módulo «Herencia y polimorfismo»: List dice qué puede hacer una lista, y ArrayList es una forma de hacerlo. Necesitas dos import: java.util.ArrayList y java.util.List. A partir de aquí, la lección no los muestra.
La idea
Índices: get, set, add, indexOf
Una lista tiene índices como un array, del 0 a size() - 1. Pero en lugar de [ ] usas métodos:
List<String> tasks = new ArrayList<>();tasks.add("Factura de marzo");tasks.add("Llamar al banco");tasks.add("Informe del almacén");
System.out.println(tasks.get(0));tasks.set(1, "Reunión en el banco");tasks.add(0, "Café con el equipo");System.out.println(tasks);System.out.println(tasks.indexOf("Informe del almacén"));System.out.println(tasks.contains("Llamar al banco"));Factura de marzo[Café con el equipo, Factura de marzo, Reunión en el banco, Informe del almacén]3falseget(i)lee, yset(i, x)reemplaza.add(i, x)inserta en el índiceiy desplaza el resto a la derecha.indexOf(x)busca y devuelve el índice o-1, ycontains(x)solo dice si está.
Más precisamente, para curiosos
- Un índice fuera de la lista detiene el programa, como con un array:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 3 out of bounds for length 3containseindexOfcomparan conequals, no con==. Por eso encuentran un texto igual, no solo el mismo objeto.- Insertar y quitar al principio es lento en una lista grande: cada elemento después del índice se mueve un lugar. Con un millón de elementos, son un millón de movimientos.
Pruébalo
¿Quién sigue?
La lista de pacientes que esperan en el médico. Juan entra, y Ana tiene cita, así que ocupa el segundo lugar.
¿Qué imprimirá el programa?
List<String> waiting = new ArrayList<>();waiting.add("Juan");waiting.add("María");waiting.add("Pedro");waiting.remove(0);waiting.add(1, "Ana");System.out.println(waiting + " " + waiting.size());remove(0) quita a Juan, y María pasa a ser la primera, en el índice 0. add(1, "Ana") inserta a Ana en el índice 1 y empuja a Pedro a la derecha. Quedan tres.
La idea
Recorrer los elementos
Recorres una lista como un array: con for-each cuando solo necesitas los elementos, o con un índice cuando también necesitas el número:
List<String> cart = new ArrayList<>();cart.add("Pan");cart.add("Café");cart.add("Mantequilla");
for (String item : cart) { System.out.println("- " + item);}for (int i = 0; i < cart.size(); i++) { System.out.println((i + 1) + ". " + cart.get(i));}- Pan- Café- Mantequilla1. Pan2. Café3. MantequillaMás precisamente, para curiosos
- No quites elementos de una lista mientras la recorres con for-each. El programa se detiene:
for (String item : cart) { if (item.equals("Pan")) { cart.remove(item); }}Exception in thread "main" java.util.ConcurrentModificationExceptionLa excepción no siempre llega. Si quitas el penúltimo elemento, el bucle termina antes y el último nunca se comprueba. Así que no cuentes con ella.
- Si tienes que quitar, recorre con un índice de atrás hacia delante. Así, quitar no desplaza los elementos que todavía no has comprobado:
List<String> cart = new ArrayList<>();cart.add("Pan");cart.add("Leche");cart.add("Pan");for (int i = cart.size() - 1; i >= 0; i--) { if (cart.get(i).equals("Pan")) { cart.remove(i); }}System.out.println(cart);[Leche]removeIf.La idea
Números en una lista: Integer
Una lista de puntuaciones se ve así, pero no compila:
ArrayList<int> scores = new ArrayList<>();Main.java:5: error: unexpected type ArrayList<int> scores = new ArrayList<>(); ^ required: reference found: intLos corchetes angulares necesitan una clase, y int no es una clase. Por eso cada tipo primitivo tiene una clase envoltorio: Integer para int, Double para double, Boolean para boolean, Character para char.
List<Integer> scores = new ArrayList<>();scores.add(85);scores.add(64);scores.add(91);
int total = 0;for (int score : scores) { total += score;}System.out.println("Media: " + (double) total / scores.size());Media: 80.0scores.add(85) recibe un int, pero la lista quiere un Integer. Java lo mete en un envoltorio sola. Esto se llama autoboxing. En el bucle, int score es lo contrario: unboxing. Casi siempre no notas la diferencia.
Más precisamente, para curiosos
- Compara los valores
Integerconequals, no con==.==comprueba si las dos variables apuntan al mismo objeto:
Integer a = 127, b = 127;Integer c = 128, d = 128;System.out.println(a == b);System.out.println(c == d);System.out.println(c.equals(d));truefalsetrueJava guarda objetos ya hechos para los números del -128 al 127, así que con 127 las dos flechas apuntan a un mismo objeto. Con 128 hay dos objetos.
- Un
Integerpuede sernull, y unintno. Si desenvuelvesnull, el programa se detiene conNullPointerException. Te lo encontrarás en la lección sobreHashMap.
Pruébalo
Encuentra el error
Un teatro guarda los asientos ocupados en una lista. Un cliente deja el asiento 2, y el programa debería imprimir [12, 7, 5]. En cambio imprime [12, 2, 5]. ¿Qué línea tiene el error?
Elige la línea con el error.
List tiene dos métodos remove: remove(int index) y remove(Object o). En remove(2) el argumento es un int, así que se llama al primero, y quita el elemento del índice 2, que es el asiento 7. Para quitar el valor 2, pasa un objeto: seats.remove(Integer.valueOf(2)). Una List<String> no tiene esta trampa, porque un texto nunca es un índice.La idea
Ordenar y una lista ya hecha
Collections.sort ordena la lista en el sitio: el texto en orden alfabético, los números por tamaño. La clase Collections también está en java.util.
List<String> cities = new ArrayList<>();cities.add("Sevilla");cities.add("Madrid");cities.add("Valencia");Collections.sort(cities);System.out.println(cities);
List<Integer> prices = new ArrayList<>(List.of(30, 5, 12));Collections.sort(prices);System.out.println(prices);[Madrid, Sevilla, Valencia][5, 12, 30]List.of(30, 5, 12) crea una lista ya hecha con los valores que enumeras. Pero es inmutable: no puedes añadir, quitar ni ordenar en ella.
List<String> days = List.of("lun", "mar", "mié");days.add("jue");Exception in thread "main" java.lang.UnsupportedOperationExceptionPor eso los precios de arriba se copian a una ArrayList nueva: new ArrayList<>(List.of(30, 5, 12)) es una lista que puedes cambiar.
Más precisamente, para curiosos
- El texto se ordena por los códigos de sus caracteres. Las mayúsculas van antes que las minúsculas, así que «Pera» va antes que «manzana»:
List<String> fruit = new ArrayList<>(List.of("manzana", "Pera", "banana", "Uva"));Collections.sort(fruit);System.out.println(fruit);[Pera, Uva, banana, manzana]- Cómo ordenar tus propios objetos, por ejemplo productos por precio, lo verás en la lección «Clases anidadas».
Ejercicio
Listas en clases
private de la clase, y main solo llama a sus métodos.1. Una estantería. Una clase BookShelf con un método addBook(String title) que pone el libro al final, y takeBook(), que devuelve y quita el primer libro (o null si la estantería está vacía). Añade count() y toString(). En main, añade «Bajo el yugo», «Tabaco» y «El candelabro de hierro», toma un libro e imprime el resto.
Tomado: Bajo el yugo2 quedan: [Tabaco, El candelabro de hierro]2. Un registro de eventos. Una clase Event con una fecha y una descripción, y una clase EventLog con los métodos addEvent(String date, String description) y getEventsBetween(String from, String to), que devuelve una lista con los eventos entre las dos fechas, incluidas. Las fechas son texto con la forma 2026-03-31. Con esta forma, el texto se ordena igual que las fechas, así que compareTo de la lección sobre texto las compara correctamente. Añade cuatro eventos: 2026-01-15 «Inventario anual», 2026-03-31 «Informe del primer trimestre», 2026-05-20 «Nuevo proveedor de café», 2026-09-01 «Nuevo curso escolar». Imprime los del 2026-03-01 al 2026-06-30.
2026-03-31 Informe del primer trimestre2026-05-20 Nuevo proveedor de café3. Un cuaderno. Una clase Note con un título y un contenido, y una clase Notebook con los métodos addNote, findNote(String title) (devuelve la nota o null), deleteNote(String title) (devuelve true si borró algo) y count(). Añade las notas «POO», «Colecciones» y «SQL», busca «Colecciones», borra «POO» y comprueba que ya no está.
Colecciones: ArrayList crece solaBorrada: POONotas: 2No hay ninguna nota de POO.4. Cálculo mental. Una clase Question con un texto y la respuesta correcta, y una clase MathGame con una lista de preguntas, un método addQuestion y un método start(Scanner in). start hace las preguntas una a una, lee la respuesta y al final dice cuántas fueron correctas. Las preguntas son 2 + 2, 3 * 4 y 15 - 9.
41272 + 2 = ¡Correcto!3 * 4 = ¡Correcto!15 - 9 = Incorrecto, la respuesta es 6.Puntuación: 2 de 3Más tareas
- Sin repetidos. Lee 6 nombres y reúnelos en una lista, saltándote los que ya están. Para la entrada Juan, María, Juan, Ana, María, Pedro la salida es
[Juan, María, Ana, Pedro]. - El producto más caro. Una List<Double> guarda precios. Encuentra el más alto y su índice, sin
Collections. - La lista al revés. Escribe un método que devuelva una lista nueva con los mismos elementos en orden inverso. No cambies el original.
- Una lista de la compra. Lee las órdenes
add milk,remove milk,listyend, y guarda la lista entre ellas. La orden de quitar un producto que no está dice «No existe ese producto.».
Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: Polimorfismo · Interfaces · Excepciones · Cadenas
- Continúa en: Pila, cola y lista enlazada · HashMap y HashSet · Códigos hash y funciones hash · Clases anidadas
- Ejercicios sobre el tema: Colecciones