JAVA Learning

Hub de Conteúdo

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.

java
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+)
java
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.

java
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:

java
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:

java
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():

java
// NoSuchElementException
Iterator it = lista.iterator();
it.next(); // OK - tem elementos
it.next(); // OK
it.next(); // OK
it.next(); // NoSuchElementException - lista vazia!

✅ CORRETO - Verificar primeiro:

java
Iterator it = lista.iterator();
if (it.hasNext()) {
    System.out.println(it.next()); // Seguro
}

6. Iterator com Set e Map

java
// 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

java
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

java
// 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
java
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! 🔁✨