Contratos de Iterable e Iterator
Comprenda las interfaces Iterable e Iterator y cómo funcionan internamente los bucles for-each.
Contratos de Iterable e Iterator es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Java Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Java Academy incluye 4 lecciones en total.
Iterable e Iterator
Iterable<T> e Iterator<T> son las interfaces que hacen posible el bucle for-each de Java. Comprenderlas le permite crear sus propias estructuras de datos compatibles con los bucles.
La interfaz Iterable
Iterable<T> tiene un método: iterator(), que devuelve un Iterator<T>. Cualquier clase que implemente Iterable puede utilizarse en un bucle for-each.
// java.lang.Iterable<T>
interface Iterable<T> {
Iterator<T> iterator();
// default: forEach, spliterator (Java 8+)
}
// Any class implementing Iterable<T> works in for-each:
class Range implements Iterable<Integer> {
private final int start, end;
Range(int start, int end) { this.start = start; this.end = end; }
public Iterator<Integer> iterator() {
return new RangeIterator(); // defined separately
}
}La interfaz Iterator
Iterator<T> tiene tres métodos: hasNext(), next() y el método opcional remove().
// java.util.Iterator<T>
interface Iterator<T> {
boolean hasNext(); // true if more elements
T next(); // returns next element, advances cursor
default void remove() { throw new UnsupportedOperationException(); }
}
// How for-each desugars internally:
// for (T item : iterable) { use(item); }
// becomes:
Iterator<T> it = iterable.iterator();
while (it.hasNext()) {
T item = it.next();
// use(item)
}Desazucarado del bucle for-each
El bucle for-each es azúcar sintáctico sobre el patrón Iterable/Iterator. Comprenderlo le ayuda a escribir sus propios Iterables correctamente.
List<String> names = List.of("Alice", "Bob", "Charlie");
// For-each (readable way)
for (String name : names) {
System.out.println(name);
}
// Equivalent explicit form
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String name = it.next();
System.out.println(name);
}Estado del cursor de Iterator
Un Iterator mantiene un cursor, es decir, una posición en la secuencia. Al llamar a next(), el cursor avanza. Una vez agotado, el iterador no se puede reiniciar.
List<Integer> nums = List.of(1, 2, 3);
Iterator<Integer> it = nums.iterator();
System.out.println(it.hasNext()); // true
System.out.println(it.next()); // 1
System.out.println(it.next()); // 2
System.out.println(it.next()); // 3
System.out.println(it.hasNext()); // false
try {
it.next(); // NoSuchElementException
} catch (java.util.NoSuchElementException e) {
System.out.println("No more elements!");
}ConcurrentModificationException
Modificar una colección mientras se recorre con un iterador explícito, fuera de Iterator.remove(), lanza ConcurrentModificationException.
List<String> list = new ArrayList<>(List.of("a", "b", "c", "d"));
// BAD: modifying collection during for-each
try {
for (String s : list) {
if ("b".equals(s)) list.remove(s); // ConcurrentModificationException!
}
} catch (java.util.ConcurrentModificationException e) {
System.out.println("Cannot modify during iteration!");
}
// GOOD: use Iterator.remove()
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if ("b".equals(it.next())) it.remove(); // safe
}
System.out.println(list); // [a, c, d]Varios iteradores
Cada llamada a iterator() devuelve un iterador nuevo e independiente. Puede haber varios iteradores activos simultáneamente sobre la misma colección.
List<Integer> nums = List.of(1, 2, 3);
Iterator<Integer> a = nums.iterator();
Iterator<Integer> b = nums.iterator();
System.out.println(a.next()); // 1
System.out.println(b.next()); // 1 (independent cursor)
System.out.println(a.next()); // 2
System.out.println(b.next()); // 2Iterable frente a Iterator
Diferencia clave:
- Iterable: una fuente que puede producir iteradores; se puede recorrer varias veces
- Iterator: un cursor sobre una secuencia; es de un solo uso y mantiene su estado
// Iterable: reusable
List<String> list = List.of("x", "y");
for (String s : list) {} // OK
for (String s : list) {} // OK again — new iterator each time
// Iterator: single-use
Iterator<String> it = list.iterator();
while (it.hasNext()) it.next();
// for (String s : it) {} // compile error — Iterator is not Iterable!Práctica: Iterable personalizado para líneas de archivo
Un lector de archivos que implementa Iterable para permitir recorrer sus líneas con un bucle for-each.
import java.io.*;
import java.util.*;
class FileLines implements Iterable<String>, Closeable {
private final BufferedReader reader;
FileLines(String path) throws IOException {
this.reader = new BufferedReader(new FileReader(path));
}
public Iterator<String> iterator() {
return new Iterator<>() {
private String nextLine = readNext();
private String readNext() {
try { return reader.readLine(); }
catch (IOException e) { return null; }
}
public boolean hasNext() { return nextLine != null; }
public String next() {
String curr = nextLine;
nextLine = readNext();
return curr;
}
};
}
public void close() throws IOException { reader.close(); }
}Método predeterminado forEach
Java 8 añadió a Iterable el método predeterminado forEach(Consumer). Es una alternativa práctica a escribir bucles explícitos.
List<String> cities = List.of("New York", "London", "Tokyo");
// for-each loop
for (String city : cities) System.out.println(city);
// forEach with lambda
cities.forEach(city -> System.out.println(city));
// forEach with method reference (most concise)
cities.forEach(System.out::println);
// For transforming: use stream
cities.stream()
.map(String::toUpperCase)
.forEach(System.out::println);El patrón Iterator en la práctica
Resumen de cuándo implementar Iterable/Iterator:
- Estructuras de datos personalizadas (árboles, grafos y listas enlazadas)
- Secuencias perezosas que generan elementos bajo demanda
- Secuencias basadas en recursos (líneas de archivo, cursor de BD y cola de mensajes)
Comprobación rápida
¿Qué excepción se lanza al modificar una colección mientras se recorre con un bucle for-each?
Repaso: contratos de Iterable e Iterator
Ideas clave:
- Iterable
tiene un método: iterator(); permite utilizar bucles for-each - Iterator
tiene hasNext(), next() y remove() opcional - El bucle for-each es azúcar sintáctico sobre el patrón Iterable/Iterator
- Llame varias veces a iterator() para obtener cursores nuevos e independientes
- Nunca modifique una colección durante un bucle for-each; utilice Iterator.remove() en su lugar
- Implemente Iterable en estructuras de datos personalizadas para admitir bucles for-each
Preguntas frecuentes
¿La lección «Contratos de Iterable e Iterator» es gratis?
Sí — el texto completo de «Contratos de Iterable e Iterator» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Java Academy, actualiza a CoddyKit PRO. El curso de Java Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Contratos de Iterable e Iterator»?
Comprenda las interfaces Iterable e Iterator y cómo funcionan internamente los bucles for-each. Practicas Java Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Java Academy?
No se requiere experiencia previa. Java Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.
¿Cuánto tiempo toma la lección «Contratos de Iterable e Iterator»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Java Academy?
Sí. Cada lección de Java Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Contratos de Iterable e Iterator
- Implementación de un iterador personalizado
- ListIterator y recorrido bidireccional
- Iteradores fail-fast frente a fail-safe