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());
addañade; con índice inserta y desplaza los siguientes.getconsulta ysetreemplaza.containseindexOfbuscan mediante igualdad.size()devuelve el número de elementos eisEmpty()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
| Array | List |
|---|---|
| Tamaño fijo | Tamaño dinámico |
array.length | lista.size() |
| Puede contener primitivas | Usa 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
lengthconsize(). - 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.