Iterable: La Capacidad de ser Recorrido
Introducción: El Reproductor de Música
¡Hola, equipo! 🎶
Hemos hablado mucho del Iterator (el mecanismo para pasar de canción). Pero, para que puedas usar un iterador, necesitas algo que sea "iterable".
Imaginad un MP3 (u ordenador, móvil...). El dispositivo en sí es un objeto Iterable. Significa que tiene la capacidad de ofrecerte una lista de canciones para que tú vayas pulsando "Siguiente".
Si una clase en Java implementa la interfaz Iterable, le está gritando al compilador: "¡Eh! Tengo cosas dentro que se pueden recorrer una a una. ¡Puedes usarme en un bucle for-each!".
Sin esta interfaz, el famoso bucle for (Elemento e : coleccion) no funcionaría. Hoy vamos a ver cómo crear nuestras propias clases recorribles.
Conceptos Fundamentales
Definición: Interfaz Iterable
Ubicada en java.lang.Iterable. Es la interfaz raíz de todas las colecciones (excepto Map).
* Contrato: Obliga a la clase a tener un método llamado iterator() que devuelva un objeto Iterator.
* Superpoder: Cualquier objeto que implemente Iterable puede ser el objetivo de la sentencia "for-each" (:) de Java.
Diferencia Clave
Iterable: Es el contenedor (la caja de galletas). Iterator: Es la mano que saca las galletas una a una.
El "Azúcar Sintáctico" del For-Each
Cuando escribís esto:
for (String nombre : nombres) {
System.out.println(nombre);
}
El compilador de Java, en secreto, lo traduce a esto:
Iterator<String> it = nombres.iterator();
while (it.hasNext()) {
String nombre = it.next();
System.out.println(nombre);
}
Iterable!
Desarrollo y Ejemplo Práctico
Vamos a crear algo que no sea una lista estándar de Java, pero que se pueda recorrer como si lo fuera.
Imaginad que creamos una clase EquipoProyecto para guardar a los alumnos de un grupo de DAW. Queremos poder hacer un for (Alumno a : miEquipo) directamente.
Paso 1: La clase de datos (Alumno)
Un POJO (Plain Old Java Object) sencillo.
public class Alumno {
private String nombre;
private int nota;
public Alumno(String nombre, int nota) {
this.nombre = nombre;
this.nota = nota;
}
@Override
public String toString() {
return nombre + " (" + nota + ")";
}
}
Paso 2: La clase Iterable (EquipoProyecto)
Aquí ocurre la magia. Implementamos Iterable<Alumno>.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
// 1. Decimos que esta clase se puede recorrer devolviendo 'Alumnos'
public class EquipoProyecto implements Iterable<Alumno> {
private String nombreEquipo;
// Usamos una lista interna para guardar los datos, pero es privada.
private List<Alumno> integrantes;
public EquipoProyecto(String nombreEquipo) {
this.nombreEquipo = nombreEquipo;
this.integrantes = new ArrayList<>();
}
public void agregarIntegrante(Alumno a) {
integrantes.add(a);
}
// 2. Este es el método OBLIGATORIO de la interfaz Iterable.
// Debemos devolver un Iterator<Alumno>.
@Override
public Iterator<Alumno> iterator() {
// Truco de experto: Como ArrayList ya sabe crear iteradores,
// delegamos el trabajo en él. ¡No reinventamos la rueda!
return integrantes.iterator();
}
// Método extra para mostrar nombre del equipo
public String getNombre() { return nombreEquipo; }
}
Paso 3: Probándolo en el Main
public class MainIterable {
public static void main(String[] args) {
// Creamos nuestro objeto personalizado
EquipoProyecto equipoAlpha = new EquipoProyecto("Alpha DAW");
equipoAlpha.agregarIntegrante(new Alumno("Lucía", 9));
equipoAlpha.agregarIntegrante(new Alumno("Marcos", 7));
equipoAlpha.agregarIntegrante(new Alumno("Sofía", 10));
System.out.println("Integrantes del equipo " + equipoAlpha.getNombre() + ":");
// ¡MAGIA! ✨
// Podemos usar el bucle for-each directamente sobre nuestro objeto 'equipoAlpha'
// Esto funciona SOLO porque EquipoProyecto implementa Iterable.
for (Alumno a : equipoAlpha) {
System.out.println(" - " + a);
}
// Si no implementáramos Iterable, tendríamos que haber hecho:
// equipoAlpha.getIntegrantes()... exponiendo la lista interna (mala encapsulación).
}
}
Diagrama Mermaid: La Relación Iterable-Iterator
Visualizad cómo el bucle for interactúa con vuestra clase.
sequenceDiagram
participant Main as Bucle For-Each
participant Equipo as EquipoProyecto (Iterable)
participant Interno as ArrayList Interno
participant It as Iterator
Main->>Equipo: Dame tu .iterator()
Equipo->>Interno: .iterator() (Delegación)
Interno-->>Equipo: new Iterator()
Equipo-->>Main: Iterator listo
loop Mientras hasNext() sea true
Main->>It: .next()
It-->>Main: Alumno
Main->>Main: Imprimir Alumno
end
¿Y si quiero una lógica de recorrido personalizada?
En el ejemplo anterior hemos delegado en el ArrayList. Pero, ¿y si quisiéramos un iterador que recorriera el equipo al revés o que solo mostrara los aprobados? Tendríamos que crear nuestra propia clase Iterator anónima.
(Solo para curiosos nivel avanzado):
@Override
public Iterator<Alumno> iterator() {
return new Iterator<Alumno>() {
private int indiceActual = 0;
@Override
public boolean hasNext() {
// Lógica personalizada: Hay siguiente si el índice no se sale
return indiceActual < integrantes.size();
}
@Override
public Alumno next() {
// Devolvemos y avanzamos
return integrantes.get(indiceActual++);
}
};
}
Tabla: Iterable vs Iterator
Es vital no confundirlos en el examen.
| Característica | Iterable (java.lang) |
Iterator (java.util) |
|---|---|---|
| Rol | El Contenedor (La Colección) | El Cursor (El Puntero) |
| Método Principal | iterator() |
hasNext(), next(), remove() |
| Uso | Permite usar for-each |
Permite recorrer y borrar manualmente |
| Analogía | La Biblioteca | El Bibliotecario que te trae libros |
Ejercicios Reflexivos
- Mapas: Intenta hacer
for (Object o : miHashMap). ¿Funciona? ¿Por qué crees queMapno implementaIterablepor defecto? (Pista: ¿Qué devolvería, la clave o el valor?). - Encapsulación: En el ejemplo de
EquipoProyecto, ¿por qué es mejor implementarIterableque simplemente crear un métodopublic List<Alumno> getLista()? (Pista: Piensa en proteger la lista para que nadie la borre desde fuera con un.clear()). - Arrays: Los arrays nativos (
int[] numeros) se pueden recorrer confor-each. ¿Significa esto que implementan la interfazIterable? (Investigación: Es un caso especial del lenguaje Java).
Para Saber Más
-
Documentación Oficial Iterable: https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Iterable.html
-
Baeldung - Guide to Iterable Interface: https://www.baeldung.com/java-iterable-interface