Iteradores em Java
A interface Collection possui um método chave chamado Iterator<E> iterator(). Esse método retorna um iterador, ou seja, um objeto que implementa a interface Iterator.
A interface Iterator apresenta a seguinte definição:
public interface Iterator<E> {
E next();
boolean hasNext();
void remove();
}Nessa implementação, o método next() obtém o elemento seguinte. O método hasNext() verifica se existe um elemento seguinte e se o fim da coleção ainda não foi atingido. Caso elementos permaneçam disponíveis, hasNext() retorna true. O método hasNext() precede o next(), pois ao alcançar o fim da coleção, next() lança a exceção NoSuchElementException. Além disso, o método remove() exclui o elemento atual, obtido pelo último chamado de next().
Um exemplo demonstra o uso de um iterador para percorrer uma coleção ArrayList:
import java.util.*;
public class Program {
public static void main(String[] args) {
ArrayList<String> states = new ArrayList<String>();
states.add("Germany");
states.add("France");
states.add("Italy");
states.add("Spain");
Iterator<String> iter = states.iterator();
while (iter.hasNext()) {
System.out.println(iter.next());
}
}
}A interface Iterator oferece funcionalidades limitadas. Um conjunto mais amplo de métodos surge com outro iterador, a interface ListIterator. Essa interface atende classes que implementam List, como LinkedList e ArrayList.
A interface ListIterator estende Iterator e define métodos adicionais:
void add(E obj): insere o objetoobjantes do elemento que seria retornado pelo próximo chamado denext().boolean hasNext(): retornatruese a coleção possui um elemento seguinte, caso contrário, retornafalse.boolean hasPrevious(): retornatruese a coleção possui um elemento anterior, caso contrário, retornafalse.E next(): retorna o elemento atual e avança para o seguinte; se não existir, lança a exceçãoNoSuchElementException.E previous(): retorna o elemento atual e retrocede para o anterior; se não existir, lança a exceçãoNoSuchElementException.int nextIndex(): retorna o índice do elemento seguinte; se não houver, retorna o tamanho da lista.int previousIndex(): retorna o índice do elemento anterior; se não houver, retorna -1.void remove(): remove o elemento atual da lista, devendo ser chamado apósnext()ouprevious(), senão lança a exceçãoIllegalStateException.void set(E obj): atribui ao elemento atual, selecionado pornext()ouprevious(), a referência ao objetoobj.
Um exemplo ilustra o uso de ListIterator:
import java.util.*;
public class Program {
public static void main(String[] args) {
ArrayList<String> states = new ArrayList<String>();
states.add("Germany");
states.add("France");
states.add("Italy");
states.add("Spain");
ListIterator<String> listIter = states.listIterator();
while (listIter.hasNext()) {
System.out.println(listIter.next());
}
// agora o elemento atual é Spain
// altera o valor desse elemento
listIter.set("Portugal");
// percorre os elementos na ordem reversa
while (listIter.hasPrevious()) {
System.out.println(listIter.previous());
}
}
}No exemplo acima, o código cria uma ArrayList com nomes de países e aplica um ListIterator para percorrê-la. Após exibir os elementos na ordem direta, o iterador modifica o último elemento para "Portugal" e, em seguida, exibe os elementos na ordem reversa, o que destaca a navegação bidirecional e a capacidade de alteração.
Resumo
- Iteradores facilitam a navegação sequencial por coleções.
- A interface
Iteratorfornece métodos básicos, comonext(),hasNext()eremove(). ListIteratorexpandeIteratorcom recursos adicionais, incluindo navegação reversa por meio deprevious()ehasPrevious().- Métodos extras em
ListIteratorabrangemadd(),set(),nextIndex()epreviousIndex(). - Exemplos apresentam iteração simples e avançada, com modificações em listas.
📝 Exercícios
Tarefa
Descrição: Você tem uma ArrayList de números inteiros. Sua tarefa é usar um Iterator para percorrer a lista e remover todos os números pares.
Por que usar um Iterator? Tentar remover elementos de uma ArrayList dentro de um loop for-each padrão lançaria uma ConcurrentModificationException. O Iterator é a forma correta e segura de fazer isso.
Código inicial:
import java.util.ArrayList;
import java.util.Iterator;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> numeros = new ArrayList<>();
numeros.add(10);
numeros.add(7);
numeros.add(22);
numeros.add(15);
numeros.add(30);
numeros.add(1);
System.out.println("Lista original: " + numeros);
// Obtenha um iterador para a lista.
// Use um loop while com o iterador para percorrer a lista.
// Dentro do loop, verifique se o número é par.
// Se for par, remova-o usando o método do iterador.
System.out.println("Lista após remover os pares: " + numeros);
// A saída esperada é: [7, 15, 1]
}
}Resposta
import java.util.ArrayList;
import java.util.Iterator;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> numeros = new ArrayList<>();
numeros.add(10);
numeros.add(7);
numeros.add(22);
numeros.add(15);
numeros.add(30);
numeros.add(1);
System.out.println("Lista original: " + numeros);
// 1. Obter o iterador da coleção.
Iterator<Integer> iterador = numeros.iterator();
// 2. Usar o padrão while(iter.hasNext()) para percorrer.
while (iterador.hasNext()) {
// 3. Obter o próximo elemento.
Integer numero = iterador.next();
// 4. Verificar a condição.
if (numero % 2 == 0) {
// 5. Usar o método remove() do próprio iterador.
iterador.remove();
}
}
System.out.println("Lista após remover os pares: " + numeros);
}
}Iterator quando se trata de modificação.
Iterator da ArrayList com numeros.iterator().while (iterador.hasNext()) é a forma padrão de usar um iterador, garantindo que não tentaremos acessar um elemento que não existe.iterador.next() avança para o próximo elemento e o retorna.iterador.remove(). Este método remove da coleção o último elemento que foi retornado por next(). É a única maneira segura de modificar uma coleção durante a iteração, pois o iterador sabe como atualizar seu estado interno para evitar a ConcurrentModificationException.