Iterator pattern en Java
⏱ Dedicación recomendada: 0 minutos
Esto considera el contenido visible y relevante, e ignora texto colapsado o marcado como opcional.
r8vnhill/
En Java, el patrón Iterator está formalmente implementado a través de las interfaces Iterator
e Iterable
, que son parte de la Java Collections Framework. Al igual que en Kotlin, Java permite iterar sobre colecciones mediante el uso de un iterador, pero para iterar directamente sobre un Iterator
, necesitas utilizar un bucle while
con hasNext()
o un bucle for
tradicional que controla el iterador.
Implementación del Patrón Iterator en Java
La interfaz Iterator
de Java define los métodos hasNext()
y next()
, mientras que la interfaz Iterable
proporciona el método iterator()
que devuelve un iterador.
Ejemplo de Implementación
Veamos un ejemplo similar al de Kotlin, en el que implementamos una colección de libros y un iterador para recorrerla en Java.
1. Clase Book
y la Colección Library
Primero, creamos una clase Book
y una clase Library
que será iterable:
- Código esencial
- Código completo
public record Book(String title, String author) {
@Override
public String toString() {
return title + " by " + author;
}
}
public class Library implements Iterable<Book> {
@Override
public Iterator<Book> iterator() {
return new BookIterator(books);
}
}
package cl.ravenhill.collections.iterator;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
public record Book(String title, String author) {
@Contract(pure = true)
@Override
public @NotNull String toString() {
return title + " by " + author;
}
}
package cl.ravenhill.collections.iterator;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Library implements Iterable<Book> {
private List<Book> books;
public Library(Book... books) {
this.books = new ArrayList<>(List.of(books));
}
@Override
public @NotNull Iterator<Book> iterator() {
return new BookIterator(books);
}
}
2. Implementación del Iterador
Ahora implementamos la clase BookIterator
que sigue la interfaz Iterator
de Java.
- Código esencial
- Código completo
class BookIterator implements Iterator<Book> {
private int position = 0;
@Override
public boolean hasNext() {
return position < books.size();
}
@Override
public Book next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return books.get(position++);
}
}
package cl.ravenhill.collections.iterator;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
class BookIterator implements Iterator<Book> {
private final List<Book> books;
private int position = 0;
public BookIterator(List<Book> books) {
this.books = books;
}
@Override
public boolean hasNext() {
return position < books.size();
}
@Override
public Book next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return books.get(position++);
}
}
En Java, NoSuchElementException
es una excepción no comprobada que se lanza cuando se intenta acceder a un elemento que no existe. A diferencia de las excepciones comprobadas, no es necesario declarar o manejar explícitamente las excepciones no comprobadas.
3. Uso del Iterador
Para usar el iterador, debes utilizar hasNext()
y next()
explícitamente o usar el iterador dentro de un bucle for
tradicional que maneje el control del iterador.
void main(String[] args) {
Library library = new Library(
new Book("Red Dragon", "Thomas Harris"),
new Book("At the Mountains of Madness", "H.P. Lovecraft"),
new Book("The Fellowship of the Ring", "J.R.R. Tolkien")
);
// Usar el iterador directamente
Iterator<Book> iterator = library.iterator();
while (iterator.hasNext()) {
Book book = iterator.next();
System.out.println(book);
}
// O usando el iterador en un bucle for tradicional
for (Iterator<Book> it = library.iterator(); it.hasNext(); ) {
System.out.println(it.next());
}
}
Unnamed classes
Unnamed Classes es una nueva característica introducida en Java 21 que permite escribir programas simples sin necesidad de declarar explícitamente una clase con nombre. Esto es útil para reducir el boilerplate en aplicaciones pequeñas o scripts que solo necesitan un método main
para ejecutarse.
Características de las Unnamed Classes:
- Menos código ceremonial: Ya no necesitas definir una clase solo para contener el método
main
. - Ideal para scripts o programas cortos: Al eliminar la declaración de la clase, Java se vuelve más accesible para escribir programas rápidos o ejemplos educativos.
Ejemplo:
En lugar de escribir una clase completa con un método main
tradicional:
class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
Con Unnamed Classes en Java 21, puedes escribirlo de forma más concisa:
void main(String[] args) {
System.out.println("Hello, World!");
}
Este enfoque es especialmente útil para pequeñas aplicaciones, scripts y pruebas, donde la simplicidad es clave.
Comparación final
Característica | Java | Kotlin |
---|---|---|
Sintaxis del patrón Iterator | El patrón Iterator es parte integral de la Java Collections Framework, implementado a través de las interfaces Iterator e Iterable , con un enfoque más detallado. | Kotlin simplifica el uso del patrón Iterator con una sintaxis más concisa y moderna. La interfaz Iterable está integrada de forma más intuitiva en las colecciones. |
Uso de for loops | Se requiere usar explícitamente hasNext() y next() , o usar un bucle for tradicional que gestione el iterador de forma manual. | Los bucles for en Kotlin trabajan directamente con Iterable , eliminando la necesidad de usar hasNext() y next() , mejorando la legibilidad. |
Compatibilidad | Java tiene compatibilidad con versiones anteriores, lo que puede requerir más código ceremonial para mantener la compatibilidad en ciertos contextos. | Kotlin mantiene una compatibilidad total con Java, pero introduce características modernas y concisas que facilitan el manejo de colecciones y patrones como el iterador. |
Beneficios y limitaciones
Beneficios
- Compatibilidad con la API estándar: En Java, el patrón Iterator está profundamente integrado en la Collections Framework, facilitando su uso en la mayoría de las estructuras de datos comunes.
- Control explícito sobre la iteración: La interfaz
Iterator
en Java ofrece control explícito sobre cuándo avanzar en la colección, lo que es útil en casos de manipulación o eliminación durante el recorrido. - Compatibilidad con versiones anteriores: Java mantiene compatibilidad hacia atrás, por lo que el patrón Iterator sigue funcionando incluso en versiones más antiguas del lenguaje.
Limitaciones
- Código más detallado: Comparado con Kotlin, el uso de iteradores en Java puede ser más ceremonial, ya que requiere controlar manualmente el ciclo de iteración con
hasNext()
ynext()
. - Menos expresividad: Aunque es funcional, la implementación en Java puede ser menos legible y expresiva que en Kotlin, donde las colecciones e iteradores se integran más fluidamente en el lenguaje.
¿Qué aprendimos?
El patrón Iterator es una solución flexible y reutilizable para recorrer colecciones sin exponer sus detalles internos, tanto en Java como en Kotlin. A lo largo de este análisis, vimos cómo ambos lenguajes abordan este patrón de manera diferente, destacando sus beneficios y limitaciones según el enfoque de cada uno.
Puntos clave
- Java proporciona una implementación formal del patrón Iterator mediante las interfaces
Iterator
eIterable
en su Collections Framework, lo que ofrece compatibilidad con versiones anteriores y control detallado de la iteración, aunque puede requerir más código ceremonial. - Kotlin, en comparación, ofrece una sintaxis más concisa y moderna, integrando el patrón Iterator directamente en las colecciones con mayor simplicidad y legibilidad, lo que lo hace más expresivo y eficiente para la mayoría de los casos de uso.
Esta comparación destaca cómo los enfoques pueden variar según el lenguaje, pero en ambos casos, el patrón Iterator sigue siendo una herramienta fundamental para trabajar con colecciones en un entorno orientado a objetos.
Bibliografías Recomendadas
- 📚 "Special Types of Java SE". (2022). C. Ullenboom, en Java: The comprehensive guide, (pp. 569–618.) Rheinwerk Publishing/SAP Press.