📋 List en Java
En este apartado vamos a estudiar una de las interfaces más importantes del framework de colecciones de Java: List.
1️⃣ ¿Qué es List?
List es una interfaz de Java que representa una secuencia ordenada de elementos.
Eso significa que en una lista:
- los elementos mantienen un orden
- cada elemento tiene una posición o índice
- se pueden guardar elementos duplicados
Ejemplo:
import java.util.ArrayList;
import java.util.List;
List<String> nombres = new ArrayList<>();
nombres.add("Ana");
nombres.add("Luis");
nombres.add("Ana");
System.out.println(nombres);
Salida:
[Ana, Luis, Ana]
Observa que:
"Ana"aparece dos veces- los elementos salen en el mismo orden en el que se añadieron
- podemos acceder a cada uno por posición
🧠 Idea clave
Una List se parece bastante a un array, pero con ventajas importantes:
- puede crecer y reducirse dinámicamente
- tiene muchos métodos útiles ya incorporados
- permite trabajar de forma más cómoda con grupos de datos
2️⃣ Características principales de List
✅ Mantiene el orden de inserción
Si añades elementos en este orden:
lista.add("rojo");
lista.add("verde");
lista.add("azul");
La lista quedará así:
[rojo, verde, azul]
✅ Permite duplicados
A diferencia de un Set, una List sí permite repetir elementos:
lista.add("Ana");
lista.add("Ana");
Resultado:
[Ana, Ana]
✅ Permite acceso por índice
Igual que en los arrays, cada elemento tiene una posición:
Índice: 0 1 2
Valor: Ana Luis Carlos
Podemos acceder así:
System.out.println(lista.get(1));
Salida:
Luis
✅ Puede almacenar objetos
Una List puede guardar:
StringIntegerDouble- objetos creados por ti, como
Alumno,Producto,Reserva, etc.
Ejemplo:
List<Integer> numeros = new ArrayList<>();
List<Producto> productos = new ArrayList<>();
3️⃣ Implementaciones principales de List
List es una interfaz, así que no se puede instanciar directamente:
❌ Incorrecto:
List<String> lista = new List<>();
✔ Correcto:
List<String> lista = new ArrayList<>();
Las principales clases que implementan List son:
| Clase | Características principales |
|---|---|
| ArrayList | Lista basada en array dinámico. Muy rápida para acceder por índice. |
| LinkedList | Lista basada en nodos enlazados. Mejor para insertar o eliminar en medio. |
| Vector | Similar a ArrayList pero sincronizado (antiguo, casi no se usa). |
| Stack | Implementa una pila (LIFO). También es una clase antigua basada en Vector. |
Pero en este tema nos vamos a centrar sobre todo en las dos más importantes y más usadas:
ArrayListLinkedList
4️⃣ ArrayList
Es la implementación de List más utilizada.
ArrayList es una implementación de List basada internamente en un array dinámico.
Es decir:
- por dentro usa un array
- pero ese array puede crecer cuando se llena
- Java se encarga automáticamente de crear uno más grande y copiar los elementos
🧠 ¿Cómo funciona internamente?
De forma simplificada, internamente ocurre algo parecido a esto:
Object[] elementos;
Cuando el ArrayList se llena:
- se crea un array más grande
- se copian los elementos antiguos
- se sigue trabajando con el nuevo array
Eso hace que para el programador sea muy cómodo, porque no tiene que preocuparse por el tamaño.
✅ Ventajas de ArrayList
- acceso muy rápido por índice
- muy cómodo de usar
- ideal cuando hacemos muchas lecturas
- suele ser la implementación más usada
⚠️ Inconvenientes de ArrayList
- insertar o borrar en medio puede ser más lento
- porque hay que desplazar elementos, ya que internamente es un array.
Ejemplo:
[Ana, Luis, Carlos, Marta]
Si borramos "Luis":
[Ana, Carlos, Marta]
Java tiene que mover los elementos posteriores una posición.
💡 Ejemplo básico con ArrayList
import java.util.ArrayList;
import java.util.List;
public class EjemploArrayList {
public static void main(String[] args) {
List<String> nombres = new ArrayList<>();
nombres.add("Ana");
nombres.add("Luis");
nombres.add("Carlos");
System.out.println(nombres);
}
}
Salida:
[Ana, Luis, Carlos]
5️⃣ LinkedList
LinkedList es una implementación de List basada en una lista enlazada.
En vez de guardar los elementos en posiciones consecutivas de un array, cada elemento se almacena en un nodo (objeto).
Cada nodo contiene:
- el dato
- una referencia al nodo siguiente
- y en Java además, en esta implementación, también una referencia al anterior
Por eso se dice que LinkedList es una lista doblemente enlazada.
🧠 ¿Cómo funciona internamente?
Simplificando mucho, sería algo parecido a esto:
[Ana] <-> [Luis] <-> [Carlos] <-> [Marta]
Cada nodo “sabe” quién va antes y quién va después.

✅ Ventajas de LinkedList
- insertar o eliminar elementos al principio o en medio puede ser más eficiente que en
ArrayList
⚠️ Inconvenientes de LinkedList
- acceder por índice es más lento
- ocupa más memoria
- en muchos casos prácticos,
ArrayListsigue siendo mejor elección
Para acceder al elemento de índice 500, por ejemplo, no puede ir directamente: tiene que recorrer nodos hasta llegar a ese.
💡 Ejemplo básico con LinkedList
import java.util.LinkedList;
import java.util.List;
public class EjemploLinkedList {
public static void main(String[] args) {
List<String> nombres = new LinkedList<>();
nombres.add("Ana");
nombres.add("Luis");
nombres.add("Carlos");
System.out.println(nombres);
}
}
Salida:
[Ana, Luis, Carlos]
6️⃣ ArrayList vs LinkedList
ArrayList
- Es como una fila de cajas contiguas.
- Ir a una posición concreta es rapidísimo.
- Pero meter o quitar algo en medio molesta, porque hay que mover lo que viene detrás.
LinkedList
- Es como una cadena de nodos enlazados.
- Insertar o quitar al principio o al final puede ser muy fácil.
- Pero llegar a una posición concreta cuesta más, porque hay que ir pasando nodo a nodo.
📌 Regla práctica
En la mayoría de ejercicios y programas:
usa
ArrayListpor defecto
Piensa en LinkedList cuando:
- hay muchas inserciones y borrados al principio o en posiciones ya localizadas
- no importa tanto el acceso rápido por índice
- o quieres reutilizarla luego como cola
7️⃣ Eficiencia de operaciones
📊 Complejidad aproximada
| Operación | ArrayList | LinkedList | Por qué |
|---|---|---|---|
Acceder por índice (get(i)) |
Muy eficiente O(1) |
Poco eficiente O(n) |
En ArrayList se va directo a la posición del array. En LinkedList hay que recorrer nodos. |
Modificar por índice (set(i, x)) |
Muy eficiente O(1) |
Poco eficiente O(n) |
Primero hay que localizar la posición; en lista enlazada eso implica recorrer. |
Añadir al final (add(x)) |
Muy eficiente amortizado O(1) |
Muy eficiente O(1) |
ArrayList suele tener hueco al final; a veces debe redimensionar O(n). LinkedList enlaza un nuevo nodo al final. |
| Insertar al principio | Poco eficiente O(n) |
Muy eficiente O(1) |
En ArrayList hay que desplazar todos los elementos. En LinkedList solo cambia enlaces. |
| Insertar en medio | Poco eficiente O(n) |
Poco eficiente en general O(n) |
En ArrayList se desplazan elementos. En LinkedList no se desplazan, pero normalmente hay que recorrer hasta llegar al nodo. |
| Eliminar al principio | Poco eficiente O(n) |
Muy eficiente O(1) |
En ArrayList todo se corre una posición. En LinkedList solo se cambia el inicio. |
| Eliminar al final | Muy eficiente O(1) |
Muy eficiente O(1) |
En ArrayList se quita el último directamente. En LinkedList también puede ser rápido si guarda referencia al último nodo. |
| Eliminar en medio | Poco eficiente O(n) |
Poco eficiente en general O(n) |
ArrayList desplaza elementos; LinkedList necesita localizar el nodo antes de quitarlo. |
| Recorrer todos los elementos | Eficiente O(n) |
Eficiente O(n) |
En ambos hay que pasar por todos. |
| Memoria | Menor consumo | Mayor consumo | LinkedList necesita nodos y referencias extra. |
🧠 ¿Qué significa esto?
O(1)
O(1) significa tiempo constante. La operación tarda prácticamente lo mismo aunque la lista sea pequeña o grande.
Ejemplo:
lista.get(5);
En ArrayList es rápido porque va directamente a la posición.
O(n)
La operación depende del número de elementos.
Cuantos más elementos haya, más puede tardar.
Ejemplo:
- buscar un nombre
- recorrer hasta una posición
- comprobar si existe un elemento
🎯 Entender que...
ArrayListes muy buena para leer por índiceLinkedListno es buena para acceder por posición muchas veces- ambas pueden usarse como
List, pero no rinden igual
8️⃣ Métodos más usados de List
Ahora vamos a ver los métodos más usados de la interfaz List.
➕ add(elemento)
Añade un elemento al final de la lista.
List<String> nombres = new ArrayList<>();//da igual que sea arrayList que LinkedList
nombres.add("Ana");
nombres.add("Luis");
System.out.println(nombres);
Salida:
[Ana, Luis]
➕ add(indice, elemento)
Inserta un elemento en una posición concreta.
nombres.add(1, "Marta");
System.out.println(nombres);
Salida:
[Ana, Marta, Luis]
👀 get(indice)
Devuelve el elemento de una posición concreta.
System.out.println(nombres.get(0));
Salida:
Ana
✏️ set(indice, elemento)
Modifica el valor de una posición.
nombres.set(1, "Carlos");
System.out.println(nombres);
Salida:
[Ana, Carlos, Luis]
❌ remove(indice)
Elimina el elemento de una posición.
nombres.remove(1);
System.out.println(nombres);
Salida:
[Ana, Luis]
❌ remove(objeto)
Elimina la primera aparición de un elemento.
nombres.remove("Ana");
System.out.println(nombres);
Salida:
[Luis]
📏 size()
Devuelve cuántos elementos tiene la lista.
System.out.println(nombres.size());
🔍 contains(objeto)
Comprueba si un elemento existe en la lista.
System.out.println(nombres.contains("Luis"));
Salida:
true
📍 indexOf(objeto)
Devuelve la posición de la primera aparición del elemento.
System.out.println(nombres.indexOf("Luis"));
Si no existe, devuelve:
-1
🧹 clear()
Elimina todos los elementos de la lista.
nombres.clear();
System.out.println(nombres);
Salida:
[]
❓ isEmpty()
Indica si la lista está vacía.
System.out.println(nombres.isEmpty());
9️⃣ Recorrer una List
🔁 Con for clásico
Muy útil si necesitas los índices.
for (int i = 0; i < nombres.size(); i++) {
System.out.println(i + " -> " + nombres.get(i));
}
🔁 Con for-each
Muy cómodo cuando solo quieres recorrer los elementos.
for (String nombre : nombres) {
System.out.println(nombre);
}
🔁 Con while
También se puede, aunque se usa menos.
int i = 0;
while (i < nombres.size()) {
System.out.println(nombres.get(i));
i++;
}
🔟 Ejemplo completo con List
import java.util.ArrayList;
import java.util.List;
public class EjemploList {
public static void main(String[] args) {
List<String> frutas = new ArrayList<>();
frutas.add("Manzana");
frutas.add("Pera");
frutas.add("Plátano");
System.out.println("Lista inicial: " + frutas);
frutas.add(1, "Fresa");
System.out.println("Tras insertar: " + frutas);
frutas.set(2, "Kiwi");
System.out.println("Tras modificar: " + frutas);
frutas.remove("Manzana");
System.out.println("Tras eliminar: " + frutas);
System.out.println("Tamaño: " + frutas.size());
System.out.println("¿Contiene Pera? " + frutas.contains("Pera"));
for (String fruta : frutas) {
System.out.println(fruta);
}
}
}
1️⃣1️⃣ Listas de objetos
Una de las partes más importantes de List en Java real es que normalmente no guardaremos solo cadenas o enteros, sino objetos.
Ejemplo:
import java.util.ArrayList;
import java.util.List;
public class Principal {
public static void main(String[] args) {
List<Alumno> alumnos = new ArrayList<>();
alumnos.add(new Alumno("Ana", 8));
alumnos.add(new Alumno("Luis", 6));
alumnos.add(new Alumno("Marta", 9));
for (Alumno a : alumnos) {
System.out.println(a.getNombre() + " - " + a.getNota());
}
}
}
Y la clase:
public class Alumno {
private String nombre;
private int nota;
public Alumno(String nombre, int nota) {
this.nombre = nombre;
this.nota = nota;
}
public String getNombre() {
return nombre;
}
public int getNota() {
return nota;
}
}
Esto conecta directamente con POO.
1️⃣2️⃣ Errores típicos con List
⚠️ Confundir size() con length
❌ Incorrecto:
lista.length //no existe
✔ Correcto:
lista.size()
Los arrays usan length, las colecciones usan size().
⚠️ Intentar usar corchetes
❌ Incorrecto:
lista[0]
✔ Correcto:
lista.get(0)
⚠️ Olvidar importar las clases
import java.util.List;
import java.util.ArrayList;
o
import java.util.LinkedList;
⚠️ Pensar que List se puede instanciar
❌ Incorrecto:
List<String> lista = new List<>();
✔ Correcto:
List<String> lista = new ArrayList<>();
⚠️ Acceder a índices fuera de rango
lista.get(10);
Si la lista no tiene esa posición, salta una excepción:
IndexOutOfBoundsException
⚠️ Confundir remove(int) con remove(Object)
Esto da problemas sobre todo con Integer.
Ejemplo:
List<Integer> numeros = new ArrayList<>();
numeros.add(10);
numeros.add(20);
numeros.add(30);
numeros.remove(1);
Esto no elimina el valor 1.
Elimina el elemento de índice 1, es decir, el 20.
1️⃣3️⃣ Buenas prácticas
✅ Programar contra la interfaz
Mejor así:
List<String> nombres = new ArrayList<>();
que así:
ArrayList<String> nombres = new ArrayList<>();
¿Por qué?
Porque si luego quieres cambiar la implementación, te resultará más fácil:
List<String> nombres = new LinkedList<>();
✅ Elegir ArrayList por defecto
Si no hay un motivo claro para otra cosa, usa:
new ArrayList<>()
✅ Usar nombres claros
List<Alumno> alumnos = new ArrayList<>();
List<Producto> productos = new ArrayList<>();
🧠 Resumen final
List es una interfaz que representa una colección ordenada de elementos.
Sus características principales son:
- mantiene el orden
- permite duplicados
- permite acceso por índice
Las implementaciones más importantes son:
ArrayList→ basada en array dinámico, muy usadaLinkedList→ basada en nodos enlazados
🎯 Idea práctica
- Usa
ArrayListen la mayoría de situaciones - Piensa en
LinkedListsi el problema encaja mejor con inserciones y borrados frecuentes
📊 Métodos más usados de List y eficiencia
| Método | Qué hace | ArrayList | LinkedList |
|---|---|---|---|
add(elemento) |
Añade al final | O(1) amortizado | O(1) |
add(indice, elemento) |
Inserta en una posición | O(n) | O(n) |
get(indice) |
Devuelve el elemento de una posición | O(1) | O(n) |
set(indice, elemento) |
Modifica el elemento de una posición | O(1) | O(n) |
remove(indice) |
Elimina el elemento de una posición | O(n) | O(n) |
remove(objeto) |
Elimina la primera aparición del elemento | O(n) | O(n) |
size() |
Devuelve cuántos elementos hay | O(1) | O(1) |
isEmpty() |
Comprueba si está vacía | O(1) | O(1) |
contains(objeto) |
Comprueba si existe un elemento | O(n) | O(n) |
indexOf(objeto) |
Devuelve la posición de la primera aparición | O(n) | O(n) |
clear() |
Elimina todos los elementos | O(n) | O(n) |