0Pricing
Java Academy · Aula

Implementação de um Iterator Personalizado

Crie uma classe de iterator personalizada para uma lista encadeada simples ou uma estrutura de intervalo.

Implementação de um Iterator Personalizado é uma aula grátis de Java Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Java Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Java Academy inclui 4 aulas no total.

Iterator personalizado

Criar um iterador personalizado oferece controle total sobre como uma estrutura de dados é percorrida. Esta lição mostra passo a passo como implementar um iterador de lista encadeada.

A classe Node

Primeiro, defina a estrutura de nós de uma lista simplesmente encadeada.

class Node<T> {
    final T value;
    Node<T> next;

    Node(T value) {
        this.value = value;
    }
}

// Building a chain: 1 -> 2 -> 3
Node<Integer> head = new Node<>(1);
head.next = new Node<>(2);
head.next.next = new Node<>(3);

Implementando o Iterator

Crie uma classe interna que implemente Iterator<T> com um cursor apontando para o nó atual.

import java.util.Iterator;
import java.util.NoSuchElementException;

class LinkedList<T> implements Iterable<T> {
    private Node<T> head;
    private int size;

    private class LinkedListIterator implements Iterator<T> {
        private Node<T> current = head; // cursor

        @Override
        public boolean hasNext() {
            return current != null;
        }

        @Override
        public T next() {
            if (!hasNext()) throw new NoSuchElementException();
            T value = current.value;
            current = current.next;
            return value;
        }
    }

    @Override
    public Iterator<T> iterator() {
        return new LinkedListIterator();
    }
}

addFirst e LinkedList completa

Adicione a capacidade de inserir nós no início e veja a classe completa em funcionamento.

class LinkedList<T> implements Iterable<T> {
    private Node<T> head;
    private int size;

    public void addFirst(T value) {
        Node<T> node = new Node<>(value);
        node.next = head;
        head = node;
        size++;
    }

    public void addLast(T value) {
        Node<T> node = new Node<>(value);
        if (head == null) { head = node; }
        else {
            Node<T> curr = head;
            while (curr.next != null) curr = curr.next;
            curr.next = node;
        }
        size++;
    }

    public int size() { return size; }

    @Override
    public Iterator<T> iterator() {
        return new LinkedListIterator();
    }
}

Usando o Iterator personalizado

Com a interface Iterable implementada, a lista encadeada funciona em laços de iteração e com forEach.

LinkedList<String> list = new LinkedList<>();
list.addLast("Alice");
list.addLast("Bob");
list.addLast("Charlie");

// For-each loop works!
for (String name : list) {
    System.out.println(name);
}
// Alice
// Bob
// Charlie

// Stream also works (Java 8+)
list.forEach(name -> System.out.println("Hello, " + name));

Iterator de intervalo

Um exemplo mais simples: um iterador sobre um intervalo numérico sem uma estrutura de dados subjacente.

class IntRange implements Iterable<Integer> {
    private final int start, end, step;

    IntRange(int start, int end, int step) {
        this.start = start; this.end = end; this.step = step;
    }
    IntRange(int start, int end) { this(start, end, 1); }

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<>() {
            int current = start;
            public boolean hasNext() { return current < end; }
            public Integer next() {
                if (!hasNext()) throw new NoSuchElementException();
                int val = current;
                current += step;
                return val;
            }
        };
    }
}

for (int n : new IntRange(0, 10, 2)) System.out.print(n + " ");
// 0 2 4 6 8

Iterator em ordem de árvore

Implementando um Iterator de BST em ordem usando uma pilha explícita — isso demonstra como os iteradores podem substituir a travessia recursiva.

import java.util.*;

class BinaryTree<T extends Comparable<T>> {
    private record TreeNode<T>(T val, TreeNode<T> left, TreeNode<T> right) {}

    private TreeNode<T> root;

    public Iterator<T> inorderIterator() {
        Deque<TreeNode<T>> stack = new ArrayDeque<>();
        pushLeft(root, stack);
        return new Iterator<>() {
            public boolean hasNext() { return !stack.isEmpty(); }
            public T next() {
                TreeNode<T> node = stack.pop();
                pushLeft(node.right(), stack);
                return node.val();
            }
        };
    }

    private void pushLeft(TreeNode<T> node, Deque<TreeNode<T>> stack) {
        while (node != null) { stack.push(node); node = node.left(); }
    }
}

Iterator preguiçoso

Os iteradores podem gerar valores de forma preguiçosa — somente quando next() é chamado. Isso é útil para sequências infinitas.

class FibonacciIterator implements Iterator<Long> {
    private long a = 0, b = 1;

    @Override public boolean hasNext() { return true; } // infinite!

    @Override public Long next() {
        long result = a;
        long next = a + b;
        a = b;
        b = next;
        return result;
    }
}

Iterator<Long> fib = new FibonacciIterator();
for (int i = 0; i < 10; i++) System.out.print(fib.next() + " ");
// 0 1 1 2 3 5 8 13 21 34

Iterator filtrado

Um iterador decorador que envolve outro iterador e ignora os elementos que não correspondem a um predicado.

import java.util.*;
import java.util.function.*;

class FilterIterator<T> implements Iterator<T> {
    private final Iterator<T> source;
    private final Predicate<T> predicate;
    private T next;
    private boolean hasNext;

    FilterIterator(Iterator<T> source, Predicate<T> predicate) {
        this.source = source; this.predicate = predicate;
        advance();
    }

    private void advance() {
        hasNext = false;
        while (source.hasNext()) {
            T candidate = source.next();
            if (predicate.test(candidate)) { next = candidate; hasNext = true; break; }
        }
    }

    public boolean hasNext() { return hasNext; }
    public T next() { T val = next; advance(); return val; }
}

List<Integer> nums = List.of(1,2,3,4,5,6,7,8,9,10);
Iterator<Integer> evens = new FilterIterator<>(nums.iterator(), n -> n % 2 == 0);
while (evens.hasNext()) System.out.print(evens.next() + " ");
// 2 4 6 8 10

Integração de Iterator com fluxos

Iteradores personalizados podem ser adaptados a fluxos usando Spliterators.spliteratorUnknownSize().

import java.util.*;
import java.util.stream.*;

Iterator<Integer> rangeIt = new IntRange(1, 6).iterator();

Stream<Integer> stream = StreamSupport.stream(
    Spliterators.spliteratorUnknownSize(rangeIt, Spliterator.ORDERED),
    false // not parallel
);

int sum = stream.mapToInt(Integer::intValue).sum();
System.out.println(sum); // 15

Remoção durante a iteração

O método opcional remove() de Iterator remove o elemento retornado pela última chamada a next() — ele precisa ser implementado explicitamente em iteradores personalizados.

class MutableLinkedList<T> implements Iterable<T> {
    // ... (full implementation)

    // Iterator with remove support
    private class RemovableIterator implements Iterator<T> {
        private Node<T> prev = null;
        private Node<T> current = head;

        public boolean hasNext() { return current != null; }
        public T next() {
            prev = (prev == null) ? null : current;
            T val = current.value;
            current = current.next;
            return val;
        }

        public void remove() {
            // Remove the last returned node
            if (prev == null) head = current;
            else prev.next = current;
            size--;
        }
    }
}

Lista de verificação de Iterator

Ao implementar um Iterator personalizado:

  • Sempre chame hasNext() antes de next()
  • Lance NoSuchElementException (não retorne nulo) de next() quando estiver vazio
  • Mantenha o iterador sem estado em relação à coleção (não armazene em cache o tamanho da coleção)
  • Use modCount para detectar modificações simultâneas, se necessário

Verificação rápida

O que next() deve lançar quando não houver mais elementos?

Recapitulação: implementando um Iterator personalizado

Principais conclusões:

  • Implemente Iterator com hasNext(), next() e remove() opcional
  • Mantenha um campo de cursor no iterador apontando para o próximo elemento
  • Lance NoSuchElementException de next() quando hasNext() for falso
  • Crie uma nova instância de iterador a cada chamada a iterator() para obter cursores independentes
  • Iteradores preguiçosos geram valores sob demanda — são úteis para sequências infinitas
  • Envolva iteradores em StreamSupport.stream() para conectá-los à API de fluxos

Perguntas Frequentes

A aula “Implementação de um Iterator Personalizado” é grátis?

Sim — o texto completo de “Implementação de um Iterator Personalizado” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Java Academy, atualize para CoddyKit PRO. O curso de Java Academy inclui 4 aulas no total.

O que vou aprender em “Implementação de um Iterator Personalizado”?

Crie uma classe de iterator personalizada para uma lista encadeada simples ou uma estrutura de intervalo. Você pratica Java Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Java Academy?

Nenhuma experiência prévia é necessária. Java Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Implementação de um Iterator Personalizado”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Java Academy?

Sim. Cada aula de Java Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Contratos de Iterable e Iterator
  2. Implementação de um Iterator Personalizado
  3. ListIterator e Percurso Bidirecional
  4. Iterators Fail-Fast versus Fail-Safe
← Voltar para Java Academy