Los iteradores se utilizan en el marco de la colección en Java para recuperar elementos uno por uno. Para obtener más detalles y una introducción relacionada con esto, consulte este enlace .
¿Por qué es necesario implementar la interfaz iterable?
Cada clase que implementa la interfaz Iterable de manera adecuada, se puede usar en el bucle For mejorado (bucle for-each). La necesidad de implementar la interfaz Iterator surge al diseñar estructuras de datos personalizadas.
Ejemplo:
for(Item item: customDataStructure) { // do stuff }
¿Cómo implementar la interfaz iterable?
Para implementar una estructura de datos iterables, necesitamos:
- Implemente la interfaz iterable junto con sus métodos en dicha estructura de datos
- Cree una clase Iterator que implemente la interfaz Iterator y los métodos correspondientes.
Podemos generalizar el pseudocódigo de la siguiente manera:
class CustomDataStructure implements Iterable<> { // code for data structure public Iterator<> iterator() { return new CustomIterator<>(this); } } class CustomIterator<> implements Iterator<> { // constructor CustomIterator<>(CustomDataStructure obj) { // initialize cursor } // Checks if the next element exists public boolean hasNext() { } // moves the cursor/iterator to next element public T next() { } // Used to remove an element. Implement only if needed public void remove() { // Default throws UnsupportedOperationException. } }
Nota : la clase Iterator también se puede implementar como una clase interna de la clase de estructura de datos, ya que no se usará en ningún otro lugar.
- ¿Cómo funcionan next() y hasNext()?
Para implementar un iterador, necesitamos un cursor o puntero para realizar un seguimiento de en qué elemento nos encontramos actualmente. Dependiendo de la estructura de datos subyacente, podemos avanzar de un elemento a otro. Esto se hace en el método next() que devuelve el elemento actual y el cursor avanza al siguiente elemento.
Antes de avanzar el puntero, verificamos si existe el siguiente elemento. es decir, podemos imaginar el código detrás de escena de la siguiente manera:While(iterator.hasNext()) { //if next element exists next(); // advance the pointer }
- Inicializar el cursor
La inicialización del cursor depende completamente de la estructura de datos. Por ejemplo, en una lista enlazada, inicializaríamos el cursor en el elemento principal. En una lista de array, inicializaríamos el cursor en el elemento 0.
Desde el punto de vista de la implementación:- Si la clase Iterator se implementa como una clase interna, simplemente podemos usar la palabra clave «esta» (por ejemplo, cursor = CustomDataStructure.this.element) para acceder al elemento deseado
- Si la clase Iterator se implementa como una clase separada, podemos pasar este objeto de la estructura de datos al constructor de la clase iterator como se muestra en el siguiente ejemplo.
El siguiente programa ilustra el uso de la interfaz iterable:
A continuación se muestra una Lista Vinculada Personalizada que utiliza Genéricos. La lista vinculada consta de objetos de Node que contienen un valor de datos genéricos y un puntero al siguiente Node. La clase proporciona algunos métodos ‘get’ estándar como getHead() y getTail(), y la función Iterator() necesaria, que debe implementarse al implementar la interfaz Iterable.
Luego se crea la clase personalizada necesaria ‘ListIterator’, que implementará la interfaz Iterator, junto con las funcionalidades de hasNext() y next() también se implementarán. Estas dos funciones forman el núcleo de la interfaz Iterable e Iterator.
import java.util.Iterator; // Custom Linked List class using Generics class List<T> implements Iterable<T> { Node<T> head, tail; // add new Element at tail of the linked list in O(1) public void add(T data) { Node<T> node = new Node<>(data, null); if (head == null) tail = head = node; else { tail.setNext(node); tail = node; } } // return Head public Node<T> getHead() { return head; } // return Tail public Node<T> getTail() { return tail; } // return Iterator instance public Iterator<T> iterator() { return new ListIterator<T>(this); } } class ListIterator<T> implements Iterator<T> { Node<T> current; // initialize pointer to head of the list for iteration public ListIterator(List<T> list) { current = list.getHead(); } // returns false if next element does not exist public boolean hasNext() { return current != null; } // return current data and update pointer public T next() { T data = current.getData(); current = current.getNext(); return data; } // implement if needed public void remove() { throw new UnsupportedOperationException(); } } // Constituent Node of Linked List class Node<T> { T data; Node<T> next; public Node(T data, Node<T> next) { this.data = data; this.next = next; } // Setter getter methods for Data and Next Pointer public void setData(T data) { this.data = data; } public void setNext(Node<T> next) { this.next = next; } public T getData() { return data; } public Node<T> getNext() { return next; } } // Driver class class Main { public static void main(String[] args) { // Create Linked List List<String> myList = new List<>(); // Add Elements myList.add("abc"); myList.add("mno"); myList.add("pqr"); myList.add("xyz"); // Iterate through the list using For Each Loop for (String string : myList) System.out.println(string); } }
abc mno pqr xyz
Publicación traducida automáticamente
Artículo escrito por sejalpawar y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA