Introducción a las Listas en Java
En Java, las listas son una de las estructuras de datos más utilizadas. Permiten almacenar colecciones de elementos de manera ordenada y proporcionan métodos para acceder, modificar y manipular estos elementos. Se encuentran en el paquete java.util
y forman parte del marco de colecciones de Java (Java Collections Framework
). A diferencia de los arrays, las listas pueden cambiar de tamaño dinámicamente.
¿Qué es una Lista?
Una lista es una colección ordenada de elementos que pueden ser duplicados. Las listas son dinámicas, lo que significa que su tamaño puede cambiar durante la ejecución del programa.
Características Principales:
- Ordenada: Los elementos tienen una posición específica en la lista.
- Indexada: Puedes acceder a los elementos por su índice.
- Dinámica: El tamaño de la lista puede crecer o reducirse según sea necesario.
- Permite duplicados: Puedes almacenar elementos repetidos.
Interfaces y Clases de Listas en Java
En Java, las listas se implementan mediante dos clases principales:
ArrayList
: Una lista basada en un array dinámico. Es rápida para acceder a elementos por índice, pero más lenta para insertar o eliminar elementos en posiciones intermedias.LinkedList
: Una lista basada en una estructura de nodos enlazados. Es más eficiente para insertar o eliminar elementos en cualquier posición, pero más lenta para acceder a elementos por índice.
Ambas clases implementan la interfaz List
, que define los métodos comunes para trabajar con listas.
Tipos de Listas en Java
Java proporciona varias implementaciones de listas, cada una con sus propias características:
1. ArrayList
- Basada en un array redimensionable.
- Acceso rápido a los elementos (O(1) en promedio).
- Inserciones y eliminaciones costosas en el medio de la lista (O(n)).
- Ideal cuando se realizan más operaciones de lectura que de modificación.
Ejemplo de uso de ArrayList
import java.util.ArrayList;
import java.util.List;
public class EjemploArrayList {
public static void main(String[] args) {
// Crear una lista de cadenas
List<String> frutas = new ArrayList<>();
// Añadir elementos a la lista
frutas.add("Manzana");
frutas.add("Banana");
frutas.add("Naranja");
// Acceder a un elemento por índice
System.out.println("Primera fruta: " + frutas.get(0));
// Modificar un elemento
frutas.set(1, "Pera");
// Eliminar un elemento
frutas.remove(2);
// Recorrer la lista
for (String fruta : frutas) {
System.out.println(fruta);
}
// Tamaño de la lista
System.out.println("Número de frutas: " + frutas.size());
}
}
Explicación del código:
ArrayList<String>
crea una lista de cadenas.add()
añade elementos a la lista.get()
accede a un elemento por su índice.set()
modifica un elemento en una posición específica.remove()
elimina un elemento por su índice.size()
devuelve el número de elementos en la lista.
Puedes ver en ListaArray: manejo dinámico de arrays, como construimos desde cero una clase similar a ArrayList
.
2. LinkedList
- Basada en una lista doblemente enlazada.
- Inserciones y eliminaciones eficientes en cualquier posición (O(1)).
- Acceso más lento a elementos específicos (O(n)).
- Recomendada cuando hay muchas operaciones de inserción y eliminación.
Ejemplo de uso de LinkedList
import java.util.LinkedList;
public class EjemploLinkedList {
public static void main(String[] args) {
LinkedList<String> tareas = new LinkedList<>();
tareas.add("Hacer la compra");
tareas.addFirst("Desayunar");
tareas.set(0, "Desayunar en casa");
tareas.addLast("Estudiar Java");
System.out.println(tareas);
}
}
3. Vector
- Similar a
ArrayList
, pero sincronizado (seguro para hilos). - Menos eficiente en programas de un solo hilo.
4. Stack
- Implementa una estructura tipo «pila» (LIFO: Last In, First Out).
- Basado en
Vector
.
Iteradores en Listas
Un iterador es un objeto que permite recorrer una lista elemento por elemento. Proporciona métodos para verificar si hay más elementos (hasNext()
), obtener el siguiente elemento (next()
) y eliminar el elemento actual (remove()
) de forma segura.
1. Borrado incorrecto
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class BorrarMal {
public static void main(String[] args) {
List<String> lista = new ArrayList<>();
lista.add("Azul");
lista.add("Verde");
lista.add("Verde");
lista.add("Naranja");
lista.add("Morado");
lista.add("Gris");
System.out.println(lista);
// Al borrar de la lista, la posición del elemento siguiente varía, por lo que se salta un verde
for (int i = 0; i < lista.size(); i++) {
if (lista.get(i).equals("Verde")) {
lista.remove(i);
}
}
// Date cuenta como aparece un verde
System.out.println(lista);
}
}
2. Uso de Iterator
Para declarar un iterador, debes darle el mismo tipo de la colección que vas a recorrer:
Iterator<Persona> iterator = personas.iterator();
En el siguiente ejemplo, como la lista es de String, el iterador también:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class EjemploIterador {
public static void main(String[] args) {
List<String> colores = new ArrayList<>();
colores.add("Rojo");
colores.add("Verde");
colores.add("Verde");
colores.add("Azul");
// Obtener un iterador --> definimos el iterador para String
Iterator<String> iterador = colores.iterator();
// Recorrer la lista con el iterador
while (iterador.hasNext()) {
String color = iterador.next();
System.out.println(color);
// Eliminar el elemento "Verde"
if (color.equals("Verde")) {
iterador.remove();
}
}
// Mostrar la lista después de la eliminación
System.out.println("Colores después de eliminar 'Verde': " + colores);
}
}
Explicación del código:
iterator()
obtiene un iterador para la lista. Recuerda que debes declarar el iterador de la misma clase que la lista.hasNext()
verifica si hay más elementos.next()
devuelve el siguiente elemento.remove()
elimina el elemento actual.
3. Uso de ListIterator
- Permite recorrer en ambas direcciones.
- Puede modificar elementos.
import java.util.ArrayList;
import java.util.ListIterator;
import java.util.List;
public class ListIteratorExample {
public static void main(String[] args) {
List<String> frutas = new ArrayList<>();
frutas.add("Manzana");
frutas.add("Plátano");
frutas.add("Naranja");
ListIterator<String> listIterator = frutas.listIterator();
while (listIterator.hasNext()) {
String fruta = listIterator.next();
System.out.println(fruta);
// Insertamos una nueva fruta antes del elemento actual
if (fruta.equals("Plátano")) {
listIterator.add("Uva");
}
}
}
}
Este código hace uso de un iterador, como el ejemplo anterior, pero en este caso usa ListIterator
para insertar una nueva fruta («Uva») antes del elemento «Plátano».
Buenas Prácticas
- Usa la interfaz
List
para declarar variables: Esto permite cambiar la implementación (ArrayList
,LinkedList
) sin modificar el código.
List<String> lista = new ArrayList<>();
- Considera el rendimiento eligiendo la estructura adecuada:
- Si se realizan inserciones y eliminaciones frecuentemente, usar
LinkedList
. - Si se accede frecuentemente a los elementos, o se requiere un acceso rápido por índice, usar
ArrayList
.
- Si se realizan inserciones y eliminaciones frecuentemente, usar
- Evitar iteraciones innecesarias:
- Utilizar
for-each
cuando sea posible. - Usar
Iterator
solo cuando se necesiten eliminar elementos mientras se recorre la lista.
- Utilizar
- Usar
ListIterator
cuando sea necesario modificar elementos:- Permite recorrer en ambas direcciones y modificar elementos en el recorrido.
Ejercicios Propuestos
- Crea una lista de números enteros y calcula la suma de todos los elementos.
- Implementa una lista de objetos
Persona
(con nombre y edad) y ordénala por edad. - Usa un iterador para eliminar todos los elementos de una lista que cumplan una condición.
Conclusión
Las listas son una herramienta esencial en Java para manejar colecciones de datos dinámicas. Con ArrayList
y LinkedList
, puedes elegir la implementación que mejor se adapte a tus necesidades. Los iteradores proporcionan una forma segura y eficiente de recorrer y manipular listas. Siguiendo buenas prácticas, podrás escribir código más limpio, eficiente y mantenible.
Deja una respuesta