Iterator em Java
Iteração Segura, Eficiente e Profissional em Coleções
1. O que é Iterator?
Iterator é uma interface que permite percorrer elementos de uma coleção sequencialmente sem conhecer sua estrutura interna.
É o padrão de design Iterator Pattern implementado no Java Collections Framework.
Iterator oferece operações seguras como remover durante a iteração, algo que não é seguro com for/foreach.
2. Conceitos Fundamentais
Iterator vs for tradicional
for acessa por índice (não funciona em Set/Map). Iterator funciona em qualquer coleção.
Iterator vs forEach
forEach é sintaxe açúcar (usa Iterator internamente). Iterator permite remove durante iteração.
Iterator vs Stream
Stream é funcional e imutável. Iterator é imperativo e permite mutação.
import java.util.*;
// Coleção com elementos
List nomes = Arrays.asList("Ana", "Bruno", "Carlos");
// 1. Iterator tradicional
Iterator iterator = nomes.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// 2. forEach (usa Iterator internamente)
for (String nome : nomes) {
System.out.println(nome);
}
// 3. for tradicional (só funciona com List)
for (int i = 0; i < nomes.size(); i++) {
System.out.println(nomes.get(i));
}
// 4. Stream (Java 8+)
nomes.stream().forEach(System.out::println);
3. Métodos do Iterator
Métodos Principais:
- hasNext() - Retorna true se há próximo elemento
- next() - Retorna próximo elemento e avança
- remove() - Remove o elemento atual da coleção
- forEachRemaining() - Processa elementos restantes (Java 8+)
List frutas = new ArrayList<>(
Arrays.asList("Maçã", "Banana", "Laranja", "Morango")
);
// hasNext() e next()
Iterator it = frutas.iterator();
while (it.hasNext()) {
String fruta = it.next();
System.out.println("Comendo: " + fruta);
}
// remove() - remover durante iteração
Iterator it2 = frutas.iterator();
while (it2.hasNext()) {
String fruta = it2.next();
if (fruta.equals("Banana")) {
it2.remove(); // Seguro! Remove da lista
}
}
System.out.println("Após remover: " + frutas);
// [Maçã, Laranja, Morango]
// forEachRemaining() - processa resto (Java 8+)
Iterator it3 = frutas.iterator();
it3.next(); // Pega primeiro
it3.forEachRemaining(System.out::println); // Processa resto
4. ListIterator - Iterator Bidirecional
ListIterator estende Iterator e permite navegar em ambas as direções em listas.
List numeros = new ArrayList<>(
Arrays.asList(1, 2, 3, 4, 5)
);
// ListIterator - bidirecional
ListIterator listIt = numeros.listIterator();
// Navegar para frente
System.out.println("Para frente:");
while (listIt.hasNext()) {
System.out.println(listIt.next());
}
// Navegar para trás
System.out.println("Para trás:");
while (listIt.hasPrevious()) {
System.out.println(listIt.previous());
}
// Começar de um índice específico
ListIterator listIt2 = numeros.listIterator(2);
System.out.println("Começando de índice 2:");
while (listIt2.hasNext()) {
System.out.println(listIt2.next());
}
// nextIndex() e previousIndex()
listIt2.next(); // Pega elemento 3
System.out.println("Próximo índice: " + listIt2.nextIndex());
System.out.println("Índice anterior: " + listIt2.previousIndex());
// set() - substitui elemento
listIt2.set(100); // Substitui 3 por 100
// add() - adiciona antes do próximo
listIt2.add(99);
System.out.println("Lista modificada: " + numeros);
5. Usando Iterator Corretamente
❌ ERRADO - Remover durante forEach:
List lista = new ArrayList<>(
Arrays.asList("A", "B", "C", "D")
);
// PERIGO: ConcurrentModificationException
for (String item : lista) {
if (item.equals("B")) {
lista.remove(item); // ERRO!
}
}
✅ CORRETO - Usar Iterator:
List lista = new ArrayList<>(
Arrays.asList("A", "B", "C", "D")
);
// SEGURO: Iterator permite remover
Iterator it = lista.iterator();
while (it.hasNext()) {
String item = it.next();
if (item.equals("B")) {
it.remove(); // OK! Seguro
}
}
System.out.println(lista); // [A, C, D]
❌ ERRADO - next() sem hasNext():
// NoSuchElementException
Iterator it = lista.iterator();
it.next(); // OK - tem elementos
it.next(); // OK
it.next(); // OK
it.next(); // NoSuchElementException - lista vazia!
✅ CORRETO - Verificar primeiro:
Iterator it = lista.iterator();
if (it.hasNext()) {
System.out.println(it.next()); // Seguro
}
6. Iterator com Set e Map
// Set - sem ordem
Set cores = new HashSet<>(
Arrays.asList("Vermelho", "Azul", "Verde")
);
// Iterator no Set
Iterator itSet = cores.iterator();
while (itSet.hasNext()) {
System.out.println(itSet.next());
}
// Map - usar entrySet()
Map idades = new HashMap<>();
idades.put("João", 25);
idades.put("Maria", 30);
idades.put("Pedro", 28);
// ❌ ERRADO - usar values()
Iterator valores = idades.values().iterator();
while (valores.hasNext()) {
System.out.println(valores.next()); // Só valores
}
// ✅ CORRETO - usar entrySet()
Iterator> itMap = idades.entrySet().iterator();
while (itMap.hasNext()) {
Map.Entry entry = itMap.next();
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
// keySet() - para apenas chaves
Iterator chaves = idades.keySet().iterator();
while (chaves.hasNext()) {
System.out.println(chaves.next());
}
7. Comparação: For vs ForEach vs Iterator vs Stream
| Aspecto | For | ForEach | Iterator | Stream |
|---|---|---|---|---|
| Funciona com | List apenas | Qualquer Iterable | Qualquer Collection | Collections |
| Remove seguro | ❌ Não | ❌ Não | ✅ Sim | ❌ Não |
| Índice disponível | ✅ Sim | ❌ Não | ❌ Não | ❌ Não |
| Bidirecional | ✅ Sim | ❌ Não | ⚠️ ListIterator | ❌ Não |
| Funcional | ❌ Não | ❌ Não | ❌ Não | ✅ Sim |
| Performance | O(1) | O(n) | O(n) | O(n) |
| Legibilidade | Boa | Excelente | Verbosa | Excelente |
8. Exemplo Prático: Sistema de Carrinho de Compras
class Item {
private String produto;
private double preco;
private int quantidade;
public Item(String produto, double preco, int quantidade) {
this.produto = produto;
this.preco = preco;
this.quantidade = quantidade;
}
public String getProduto() { return produto; }
public double getPreco() { return preco; }
public int getQuantidade() { return quantidade; }
public double getTotal() { return preco * quantidade; }
public String toString() {
return produto + " (R$ " + preco + " x " + quantidade + ")";
}
}
class Carrinho {
private List- itens = new ArrayList<>();
public void adicionarItem(Item item) {
itens.add(item);
}
// Remover itens específicos usando Iterator
public void removerItemPorNome(String nome) {
Iterator
- it = itens.iterator();
while (it.hasNext()) {
Item item = it.next();
if (item.getProduto().equals(nome)) {
it.remove();
System.out.println("Removido: " + nome);
}
}
}
// Aplicar desconto em itens caros
public void removerItensCaros(double precoMaximo) {
Iterator
- it = itens.iterator();
int removidos = 0;
while (it.hasNext()) {
Item item = it.next();
if (item.getPreco() > precoMaximo) {
System.out.println("Muito caro: " + item);
it.remove();
removidos++;
}
}
System.out.println("Total removidos: " + removidos);
}
// Listar com Iterator
public void listar() {
System.out.println("=== CARRINHO ===");
if (itens.isEmpty()) {
System.out.println("Vazio");
return;
}
Iterator
- it = itens.iterator();
int numero = 1;
while (it.hasNext()) {
System.out.println(numero + ". " + it.next());
numero++;
}
}
// Total
public double calcularTotal() {
double total = 0;
Iterator
- it = itens.iterator();
while (it.hasNext()) {
total += it.next().getTotal();
}
return total;
}
}
// USO
Carrinho carrinho = new Carrinho();
carrinho.adicionarItem(new Item("Notebook", 3000, 1));
carrinho.adicionarItem(new Item("Mouse", 50, 2));
carrinho.adicionarItem(new Item("Teclado", 150, 1));
carrinho.listar();
System.out.println("Total: R$ " + carrinho.calcularTotal());
carrinho.removerItemPorNome("Mouse");
carrinho.listar();
System.out.println("Total: R$ " + carrinho.calcularTotal());
carrinho.removerItensCaros(500);
carrinho.listar();
9. Criando Iterador Customizado
// Coleção customizada
public class MinhaColecao implements Iterable {
private T[] elementos;
private int tamanho;
@SuppressWarnings("unchecked")
public MinhaColecao(int capacidade) {
elementos = new Object[capacidade];
tamanho = 0;
}
public void adicionar(T elemento) {
if (tamanho < elementos.length) {
elementos[tamanho++] = elemento;
}
}
// Implementar Iterable
@Override
public Iterator iterator() {
return new MeuIterator();
}
// Iterator interno
private class MeuIterator implements Iterator {
private int indice = 0;
@Override
public boolean hasNext() {
return indice < tamanho;
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return elementos[indice++];
}
@Override
public void remove() {
if (indice == 0) {
throw new IllegalStateException();
}
// Remover elemento anterior
for (int i = indice - 1; i < tamanho - 1; i++) {
elementos[i] = elementos[i + 1];
}
tamanho--;
indice--;
}
}
}
// USO
MinhaColecao colecao = new MinhaColecao<>(5);
colecao.adicionar("A");
colecao.adicionar("B");
colecao.adicionar("C");
// Usa Iterator customizado
for (String item : colecao) {
System.out.println(item);
}
// Com Iterator explícito
Iterator it = colecao.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
10. Boas Práticas com Iterator
✓ FAÇA:
- Use Iterator para remover durante iteração
- Sempre verifique hasNext() antes de next()
- Use entrySet() com Map, não keySet() + get()
- Use ListIterator para listas bidirecional
- Implemente Iterable em coleções customizadas
✗ EVITE:
- Não remova usando a coleção durante forEach
- Não reutilize o mesmo Iterator múltiplas vezes
- Não chame next() sem hasNext()
- Não misture modificações (add/remove) com Iterator
- Não use for com Set (sem índice)
11. Iterator vs Stream - Quando Usar?
Use Iterator quando:
- Precisa remover elementos durante iteração
- Quer trabalhar com Set (sem ordem)
- Precisa de bidirecional (ListIterator)
- Busca máxima performance
Use Stream quando:
- Quer transformações funcionais (map, filter)
- Precisa de parallelismo
- Trabalha com expressões lambda
- Busca código mais legível
List numeros = Arrays.asList(1, 2, 3, 4, 5);
// Iterator - remover pares
Iterator it = numeros.iterator();
while (it.hasNext()) {
if (it.next() % 2 == 0) {
it.remove();
}
}
System.out.println(numeros); // [1, 3, 5]
// Stream - transformar funcionalmente
List dobrados = numeros.stream()
.map(n -> n * 2)
.collect(Collectors.toList());
System.out.println(dobrados); // [2, 6, 10]
// Iterator é melhor para remover, Stream para transformar
12. Exercícios Práticos
Exercício 1: Filtrar com Iterator
Use Iterator para remover números menores que 10 de uma lista.
Exercício 2: ListIterator Bidirecional
Implemente navegação para frente e para trás em uma lista.
Exercício 3: Remover Duplicatas
Use Iterator para remover elementos duplicados.
Exercício 4: Iterator Customizado
Crie uma classe que implemente Iterable com Iterator próprio.
Exercício 5: Modificar Durante Iteração
Use Iterator para modificar elementos sem ConcurrentModificationException.
Conclusão
Iterator é essencial para iteração segura em coleções Java, especialmente ao remover elementos.
Escolha entre for, forEach, Iterator ou Stream baseado na sua necessidade específica.
Domine Iterator e sua programação Java será muito mais robusta e profissional! 🔁✨