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 objetoobj
antes do elemento que seria retornado pelo próximo chamado denext()
.boolean hasNext()
: retornatrue
se a coleção possui um elemento seguinte, caso contrário, retornafalse
.boolean hasPrevious()
: retornatrue
se 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
Iterator
fornece métodos básicos, comonext()
,hasNext()
eremove()
. ListIterator
expandeIterator
com recursos adicionais, incluindo navegação reversa por meio deprevious()
ehasPrevious()
.- Métodos extras em
ListIterator
abrangemadd()
,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
.