Buscar..


Introducción

El java.util.Iterator es la interfaz estándar de Java SE para el objeto que implementa el patrón de diseño del iterador. La interfaz java.lang.Iterable es para objetos que pueden proporcionar un iterador.

Observaciones

Es posible iterar sobre una matriz utilizando el bucle for -each, aunque las matrices java no implementan Iterable; la iteración se realiza mediante JVM utilizando un índice no accesible en segundo plano.

Usando Iterable en for loop

Las clases que implementan Iterable<> interfaz se pueden utilizar en for bucles. En realidad, esto es solo azúcar sintáctica para obtener un iterador del objeto y usarlo para obtener todos los elementos secuencialmente; hace que el código sea más claro, más rápido de escribir, y menos propenso a errores.

public class UsingIterable {

    public static void main(String[] args) {
        List<Integer> intList = Arrays.asList(1,2,3,4,5,6,7);
        
        // List extends Collection, Collection extends Iterable
        Iterable<Integer> iterable = intList;
        
        // foreach-like loop
        for (Integer i: iterable) {
            System.out.println(i);
        }
        
        // pre java 5 way of iterating loops
        for(Iterator<Integer> i = iterable.iterator(); i.hasNext(); ) {
            Integer item = i.next();
            System.out.println(item);
        }
    }
}

Usando el iterador crudo

Si bien el uso del bucle foreach (o "bucle extendido para") es simple, a veces es beneficioso usar el iterador directamente. Por ejemplo, si desea generar un conjunto de valores separados por comas, pero no quiere que el último elemento tenga una coma:

List<String> yourData = //...
Iterator<String> iterator = yourData.iterator();
while (iterator.hasNext()){
    // next() "moves" the iterator to the next entry and returns it's value.
    String entry = iterator.next();
    System.out.print(entry);
    if (iterator.hasNext()){
        // If the iterator has another element after the current one:
        System.out.print(",");
    }
}

Esto es mucho más fácil y claro que tener una variable isLastEntry o hacer cálculos con el índice de bucle.

Creando tu propio iterable.

Para crear su propio Iterable como con cualquier interfaz, simplemente implemente los métodos abstractos en la interfaz. Para Iterable solo hay uno que se llama iterator() . Pero su tipo de retorno Iterator es en sí mismo una interfaz con tres métodos abstractos. Puede devolver un iterador asociado con alguna colección o crear su propia implementación personalizada:

public static class Alphabet implements Iterable<Character> {

    @Override
    public Iterator<Character> iterator() {
        return new Iterator<Character>() {
            char letter = 'a';

            @Override
            public boolean hasNext() {
                return letter <= 'z';
            }

            @Override
            public Character next() {
                return letter++;
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException("Doesn't make sense to remove a letter");
            }
        };
    }
}

Usar:

public static void main(String[] args) {
    for(char c : new Alphabet()) {
        System.out.println("c = " + c);
    }
}

El nuevo Iterator debe venir con un estado que apunta al primer elemento, y cada llamada a la siguiente actualiza su estado para apuntar a la siguiente. El hasNext() comprueba si el iterador está al final. Si el iterador estuviera conectado a una colección modificable, entonces se podría implementar el método opcional remove() del iterador para eliminar el elemento al que se apunta actualmente desde la colección subyacente.

Eliminar elementos utilizando un iterador

El método Iterator.remove() es un método opcional que elimina el elemento devuelto por la llamada anterior a Iterator.next() . Por ejemplo, el siguiente código rellena una lista de cadenas y luego elimina todas las cadenas vacías.

List<String> names = new ArrayList<>();
names.add("name 1");
names.add("name 2");
names.add("");
names.add("name 3");
names.add("");
System.out.println("Old Size : " + names.size());
Iterator<String> it = names.iterator();
while (it.hasNext()) {
  String el = it.next();
  if (el.equals("")) {
    it.remove();
  }
}
System.out.println("New Size : " + names.size());

Salida:

Old Size : 5
New Size : 3

Tenga en cuenta que el código anterior es la forma segura de eliminar elementos al iterar una colección típica. Si, por el contrario, intenta eliminar elementos de una colección como esta:

for (String el: names) {
    if (el.equals("")) {
        names.remove(el); // WRONG!
    }
}

una colección típica (como ArrayList ) que proporciona a los iteradores una semántica de iteradores de error rápido lanzará una ConcurrentModificationException .

El método remove() solo puede ser llamado (una vez) después de una llamada next() . Si se llama antes de llamar a next() o si se llama dos veces después de la llamada next() , entonces la llamada remove() lanzará una IllegalStateException .

La operación de remove se describe como una operación opcional ; Es decir, no todos los iteradores lo permitirán. Los ejemplos en los que no se admite incluyen iteradores para colecciones inmutables, vistas de solo lectura de colecciones o colecciones de tamaño fijo. Si se llama a remove() cuando el iterador no admite la eliminación, lanzará una UnsupportedOperationException .



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow