Iteradores en Java

Un cursor de Java es un iterador, que se utiliza para iterar, atravesar o recuperar los elementos de un objeto Collection o Stream uno por uno. Hay tres cursores en Java .

  1. iterador
  2. Enumeración
  3. ListIterator

Nota: SplitIterator también se puede considerar como un cursor, ya que es solo un tipo de iterador.

1. iterador

Los iteradores en Java se utilizan en el marco de la colección para recuperar elementos uno por uno. Es un iterador universal ya que podemos aplicarlo a cualquier objeto Collection. Al usar Iterator, podemos realizar operaciones de lectura y eliminación. Es una versión mejorada de Enumeración con la funcionalidad adicional de eliminar un elemento.

El iterador debe usarse siempre que queramos enumerar elementos en todas las interfaces implementadas del marco de la colección como Set, List, Queue, Deque y todas las clases implementadas de la interfaz Map. Iterator es el único cursor disponible para todo el marco de la colección.
El objeto iterador se puede crear llamando al método iterator() presente en la interfaz de colección.

Sintaxis:

Iterator itr = c.iterator();

Nota: Aquí «c» es cualquier objeto de colección. itr es de tipo interfaz de iterador y se refiere a «c».

Métodos de interfaz de iterador en Java

La interfaz del iterador define los tres métodos que se enumeran a continuación:

1. hasNext(): Devuelve verdadero si la iteración tiene más elementos.

public boolean hasNext();

2. next(): Devuelve el siguiente elemento de la iteración. Lanza NoSuchElementException si no hay más elementos presentes.

public Object next();

3. remove(): Elimina el siguiente elemento en la iteración. Este método se puede llamar solo una vez por llamada a next().

public void remove();

Nota: el método remove() puede arrojar dos excepciones, a saber, las siguientes:

  • UnsupportedOperationException : si la operación de eliminación no es compatible con este iterador
  • IllegalStateException : si aún no se ha llamado al siguiente método, o si ya se ha llamado al método de eliminación después de la última llamada al siguiente método.

¿Cómo funciona Java Iterator internamente?

 En esta sección, intentaremos comprender cómo funcionan internamente Java Iterator y sus métodos. Tomemos el siguiente objeto LinkedList para entender esta funcionalidad.

List<String> cities = new LinkedList<>(); 
cities.add("G-1"); 
cities.add("G-2"); 
cities.add("G-3"); 
. 
. 
. 
cities.add("G-n");

Ahora, vamos a crear un objeto Iterator en el objeto List como se muestra a continuación:

Iterator<String> citiesIterator = cities.iterator();

El iterador «citiesIteartor» se verá así:

Aquí el cursor del iterador apunta antes del primer elemento de la lista.

Ahora, ejecutaremos el siguiente fragmento de código.

citiesIterator.hasNext();
citiesIterator.next();

Cuando ejecutamos el fragmento de código anterior, el cursor del iterador apunta al primer elemento de la lista, como se muestra en el diagrama anterior.

Ahora, ejecutaremos el siguiente fragmento de código.

citiesIterator.hasNext();
citiesIterator.next();

Cuando ejecutamos el fragmento de código anterior, el cursor del iterador apunta al segundo elemento de la lista, como se muestra en el diagrama anterior. Realice este proceso para llegar al cursor del iterador hasta el elemento final de la lista.

Después de leer el elemento final, si ejecutamos el siguiente fragmento de código, devuelve un valor «falso».

citiesIterator.hasNext();

Como el cursor del iterador apunta después del elemento final de la lista, el método hasNext() devuelve un valor falso.

Nota: Después de observar todos estos diagramas, podemos decir que Java Iterator solo admite la iteración de dirección hacia adelante, como se muestra en el siguiente diagrama. Por lo que también se conoce como Cursor Unidireccional.

Ejemplo:

Java

// Java program to Demonstrate Iterator
 
// Importing ArrayList and Iterator classes
// from java.util package
import java.util.ArrayList;
import java.util.Iterator;
 
// Main class
public class Test {
    // Main driver method
    public static void main(String[] args)
    {
        // Creating an ArrayList class object
        // Declaring object of integer type
        ArrayList<Integer> al = new ArrayList<Integer>();
 
        // Iterating over the List
        for (int i = 0; i < 10; i++)
            al.add(i);
 
        // Printing the elements in the List
        System.out.println(al);
 
        // At the beginning itr(cursor) will point to
        // index just before the first element in al
        Iterator<Integer> itr = al.iterator();
 
        // Checking the next element  where
        // condition holds true till there is single element
        // in the List using hasnext() method
        while (itr.hasNext()) {
            //  Moving cursor to next element
            int i = itr.next();
 
            // Getting elements one by one
            System.out.print(i + " ");
 
            // Removing odd elements
            if (i % 2 != 0)
                itr.remove();
        }
 
        // Command for next line
        System.out.println();
 
        // Printing the elements inside the object
        System.out.println(al);
    }
}
Producción

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0 1 2 3 4 5 6 7 8 9 
[0, 2, 4, 6, 8]

Iterador dividido

Los divisores, como otros iteradores, son para atravesar los elementos de una fuente. Una fuente puede ser una colección , un canal de E/S o una función de generador. Se incluye en JDK 8 para admitir un recorrido paralelo eficiente (programación paralela) además del recorrido secuencial. La interfaz Java Spliterator es un iterador interno que divide el flujo en partes más pequeñas. Estas piezas más pequeñas se pueden procesar en paralelo.

Nota: En la programación de la vida real, es posible que nunca necesitemos usar Spliterator directamente. En operaciones normales, se comportará exactamente igual que Java Iterator.

Ventajas del iterador de Java

  • Podemos usarlo para cualquier clase de Colección.
  • Admite operaciones de LECTURA y ELIMINACIÓN.
  • Es un cursor universal para API de colección.
  • Los nombres de los métodos son simples y fáciles de usar.

Además, existen ciertas limitaciones de Iterator que se enumeran a continuación: 

Limitaciones del iterador de Java

  • En operaciones CRUD, NO admite operaciones CREAR y ACTUALIZAR.
  • Solo admite la iteración de dirección directa que es un iterador unidireccional.
  • Compare con Spliterator, NO admite la iteración de elementos en paralelo, lo que significa que solo admite la iteración secuencial.
  • Compare con Spliterator, NO admite un mejor rendimiento para iterar un gran volumen de datos.

2. Enumeración

Es una interfaz utilizada para obtener elementos de colecciones heredadas (Vector, Hashtable). La enumeración es el primer iterador presente de JDK 1.0, los descansos se incluyen en JDK 1.2 con más funcionalidad. Las enumeraciones también se usan para especificar los flujos de entrada a un SequenceInputStream . Podemos crear un objeto de enumeración llamando al método de elements() de clase vectorial en cualquier objeto vectorial  

// Here "v" is an Vector class object. e is of
// type Enumeration interface and refers to "v"
Enumeration e = v.elements();

Hay dos métodos en la interfaz de enumeración, a saber: 

1. public boolean hasMoreElements(): Este método prueba si esta enumeración contiene más elementos o no.

2. Public Object nextElement(): este método devuelve el siguiente elemento de esta enumeración. Lanza NoSuchElementException si no hay más elementos presentes

Java

// Java program to demonstrate Enumeration
 
// Importing Enumeration and Vector classes
// from java.util package
import java.util.Enumeration;
import java.util.Vector;
 
// Main class
public class Test
{
    // Main driver method
    public static void main(String[] args)
    {
        // Creating a vector object
        Vector v = new Vector();
       
      // Iterating over vector object
      for (int i = 0; i < 10; i++)
            v.addElement(i);
       
      // Printing elements in vector object 
      System.out.println(v);
 
        // At beginning e(cursor) will point to
        // index just before the first element in v
        Enumeration e = v.elements();
 
        // Checking the next element availability where
        // condition holds true till there is a single element
      // remaining in the List
        while (e.hasMoreElements())
        {
            // Moving cursor to next element
            int i = (Integer)e.nextElement();
 
            // Print above elements in object
            System.out.print(i + " ");
        }
    }
}

Producción: 

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0 1 2 3 4 5 6 7 8 9 

Hay ciertas limitaciones de enumeración que son las siguientes: 

  • La enumeración es solo para clases heredadas (Vector, Hashtable). Por lo tanto, no es un iterador universal.
  • Las operaciones de eliminación no se pueden realizar mediante la enumeración.
  • Solo es posible la iteración en la dirección de avance.

Similitudes entre la enumeración de Java y el iterador

  • Ambos son cursores de Java.
  • Ambos se utilizan para iterar una colección de elementos de objeto uno por uno.
  • Ambos admiten operaciones de LECTURA o Recuperación.
  • Ambos son cursores Java unidireccionales, lo que significa que solo admiten la iteración de dirección hacia adelante.

Diferencias entre la enumeración de Java y el iterador

La siguiente tabla describe las diferencias entre la enumeración de Java y el iterador:

Enumeración iterador
Introducido en Java 1.0 Introducido en Java 1.2
Interfaz heredada Interfaz no heredada
Se utiliza para iterar solo las clases de Legacy Collection. Podemos usarlo para cualquier clase de Colección.
Solo admite la operación de LECTURA. Admite operaciones de LECTURA y ELIMINACIÓN.
No es Cursor Universal. Es un Cursor Universal.
Nombres de métodos largos. Nombres de métodos simples y fáciles de usar.

3. Iterador de lista

Solo es aplicable para las clases implementadas de la colección List como ArrayList, LinkedList, etc. Proporciona iteración bidireccional. ListIterator debe usarse cuando queremos enumerar elementos de List. Este cursor tiene más funcionalidad (métodos) que el iterador. El objeto ListIterator se puede crear llamando al método listIterator() presente en la interfaz List.
 

ListIterator ltr = l.listIterator();

Nota: Aquí “l” es cualquier objeto Lista, ltr es de tipo. interfaz ListIterator y se refiere a «l». La interfaz ListIterator amplía la interfaz Iterator. Entonces, los tres métodos de la interfaz Iterator están disponibles para ListIterator. Además, hay seis métodos más. 

1. Dirección de avance

1.1 hasNext(): Devuelve verdadero si la iteración tiene más elementos

public boolean hasNext();

1.2 next(): Igual que el método next() de Iterator. Devuelve el siguiente elemento de la iteración.

public Object next();

1.3 nextIndex(): Devuelve el índice del siguiente elemento o el tamaño de la lista si el iterador de la lista está al final de la lista.

public int nextIndex();

2. Dirección hacia atrás

2.1 hasPrevious(): Devuelve verdadero si la iteración tiene más elementos mientras se desplaza hacia atrás.

public boolean hasPrevious();

2.2 anterior(): Devuelve el elemento anterior en la iteración y puede lanzar NoSuchElementException si no hay más elementos presentes.

public Object previous();

2.3 anteriorIndex(): Devuelve el índice del elemento anterior o -1 si el iterador de la lista está al principio de la lista,

public int previousIndex();

3. Otros métodos

3.1 remove(): Igual que el método remove() de Iterator. Elimina el siguiente elemento en la iteración.

public void remove();

3.2 set(Object obj): Reemplaza el último elemento devuelto por next() o previous() con el elemento especificado.

public void set(Object obj); 

3.3 add(Object obj): Inserta el elemento especificado en la lista en la posición anterior al elemento que devolvería next()

public void add(Object obj);

Claramente, los tres métodos que ListIterator hereda de Iterator ( hasNext() , next() y remove() ) hacen exactamente lo mismo en ambas interfaces. hasPrevious () y las operaciones anteriores son análogos exactos de hasNext() y next() . Las primeras operaciones se refieren al elemento anterior al cursor (implícito), mientras que la última se refiere al elemento posterior al cursor. La operación anterior mueve el cursor hacia atrás, mientras que la siguiente lo mueve hacia adelante.

ListIterator no tiene ningún elemento actual; la posición del cursor siempre se encuentra entre el elemento que devolvería una llamada a anterior() y el elemento que devolvería una llamada a siguiente().

1. El método set() puede lanzar 4 excepciones. 

  • UnsupportedOperationException: si la operación de configuración no es compatible con este iterador de lista
  • ClassCastException: si la clase del elemento especificado impide que se agregue a esta lista
  • IllegalArgumentException: si algún aspecto del elemento especificado impide que se agregue a esta lista
  • IllegalStateException: si no se ha llamado ni al siguiente ni al anterior, o se ha llamado a eliminar o agregar después de la última llamada al siguiente o al anterior

2. El método add() puede lanzar 3 excepciones. 

  • UnsupportedOperationException: si el método add no es compatible con este iterador de lista
  • ClassCastException: si la clase del elemento especificado impide que se agregue a esta lista
  • IllegalArgumentException: si algún aspecto de este elemento impide que se agregue a esta lista

Ejemplo:

Java

// Java program to demonstrate ListIterator
 
// Importing ArrayList and List iterator classes
// from java.util package
import java.util.ArrayList;
import java.util.ListIterator;
 
// Main class
public class Test {
    // Main driver method
    public static void main(String[] args)
    {
        // Creating an object of ArrayList class
        ArrayList al = new ArrayList();
 
        // Iterating over Arraylist object
        for (int i = 0; i < 10; i++)
 
            // Adding elements to the Arraylist object
            al.add(i);
 
        // Print and display all elements inside object
        // created above
        System.out.println(al);
 
        // At beginning ltr(cursor) will point to
        // index just before the first element in al
        ListIterator ltr = al.listIterator();
 
        // Checking the next element availability
        while (ltr.hasNext()) {
            //  Moving cursor to next element
            int i = (Integer)ltr.next();
 
            // Getting even elements one by one
            System.out.print(i + " ");
 
            // Changing even numbers to odd and
            // adding modified number again in
            // iterator
            if (i % 2 == 0) {
                // Change to odd
                i++;
                // Set method to change value
                ltr.set(i);
                // To add
                ltr.add(i);
            }
        }
 
        // Print and display statements
        System.out.println();
        System.out.println(al);
    }
}

Producción: 

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0 1 2 3 4 5 6 7 8 9 
[1, 1, 1, 3, 3, 3, 5, 5, 5, 7, 7, 7, 9, 9, 9]

Nota: Del mismo modo, existen ciertas limitaciones con ListIterator . Es el iterador más poderoso, pero solo es aplicable para las clases implementadas en List, por lo que no es un iterador universal.

Puntos importantes

  1. Tenga en cuenta que inicialmente, cualquier referencia de iterador apuntará al índice justo antes del índice del primer elemento de una colección.
  2. No creamos objetos de Enumeración, Iterador, ListIterator porque son interfaces. Usamos métodos como elements(), iterador(), listIterator() para crear objetos. Estos métodos tienen una clase interna anónima que amplía las interfaces respectivas y devuelve este objeto de clase.

Nota: El símbolo $ en el nombre de la clase de referencia es una prueba de que se utiliza el concepto de clases internas y se crean estos objetos de clase. 

Esto se puede verificar con el siguiente código. Para obtener más información sobre la clase interna, consulte 

Java

// Java program to demonstrate iterators references
 
// Importing required classes from java.util package
import java.util.Enumeration;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Vector;
 
// Main class
public class GFG {
   
    // Main driver method
    public static void main(String[] args)
    {
        // Creating an object of Vector class
        Vector v = new Vector();
 
        // Creating three iterators
        Enumeration e = v.elements();
        Iterator itr = v.iterator();
        ListIterator ltr = v.listIterator();
 
        // Print class names of iterators
        // using getClass() and getName() methods
        System.out.println(e.getClass().getName());
        System.out.println(itr.getClass().getName());
        System.out.println(ltr.getClass().getName());
    }
}
Producción

java.util.Vector$1
java.util.Vector$Itr
java.util.Vector$ListItr

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *