CodeGym /Cursos /JAVA 25 SELF /Queue, Deque, Stack: trabalhando com filas e pilhas

Queue, Deque, Stack: trabalhando com filas e pilhas

JAVA 25 SELF
Nível 27 , Lição 2
Disponível

1. Interface Queue: fila clássica (FIFO)

Em programação, como na vida, há situações em que não basta armazenar um conjunto de elementos, mas é importante controlar a ordem de processamento. Imagine uma fila no supermercado: quem está mais perto do início é atendido primeiro. Esse é o princípio FIFO — “primeiro a entrar — primeiro a sair”. Já uma pilha de pratos no armário funciona segundo o princípio LIFO — “último a entrar — primeiro a sair”. Em Java, esses princípios correspondem às coleções: filas Queue, filas de duas pontas Deque e pilhas Stack.

Onde se aplicam:

  • Processamento de tarefas por ordem de chegada (fila de tarefas, impressão de documentos, processamento de eventos).
  • Implementação de desfazer/refazer (undo/redo) — pilha.
  • Análise de expressões, travessia de árvores e grafos (busca em largura/profundidade) e muito mais.

O que é uma fila?

Uma fila (Queue) é uma coleção baseada no princípio FIFO. Os elementos são adicionados ao final e removidos do início. Como na loja: quem chegou primeiro é atendido primeiro.

Métodos principais da interface Queue

Método O que faz Retorno
offer(e)
Adiciona o elemento ao final (sem exceção) true/false
add(e)
Adiciona o elemento ao final (lança exceção) true/Exception
poll()
Remove e retorna o primeiro elemento elemento/null
remove()
Remove e retorna o primeiro elemento elemento/Exception
peek()
Retorna o primeiro elemento, sem remover elemento/null
element()
Retorna o primeiro elemento, sem remover elemento/Exception

Você deve ter notado pares de métodos com comportamento semelhante. A diferença está na “suavidade”: offer, poll, peek retornam um valor especial em caso de falha (geralmente null ou false) e não lançam exceções, enquanto add, remove, element lançam exceções em situações de borda (fila vazia, às vezes estouro).

Exemplo: fila de tarefas

import java.util.*;

public class QueueDemo {
    public static void main(String[] args) {
        Queue<String> tasks = new LinkedList<>();
        tasks.offer("Escovar os dentes");
        tasks.offer("Fazer exercícios");
        tasks.offer("Tomar café");

        while (!tasks.isEmpty()) {
            String task = tasks.poll(); // Pegamos a tarefa do início da fila
            System.out.println("Executando: " + task);
        }
    }
}

Saída:

Executando: Escovar os dentes
Executando: Fazer exercícios
Executando: Tomar café

Por que o LinkedList é usado com frequência?

Uma interface é um contrato, e há várias implementações. Muitas vezes usa-se LinkedList, pois ele adiciona/remove rapidamente em ambas as pontas. No entanto, uma ótima alternativa é ArrayDeque. Há também variantes especializadas: PriorityQueue (fila por prioridades), sobre a qual falaremos abaixo.

2. Interface Deque: fila de duas pontas

Deque (Double Ended Queue, “deque”) é uma fila em que é possível adicionar e remover elementos em ambas as pontas: do início e do fim. Como um ônibus com duas portas: dá para entrar/sair de qualquer lado.

Deque = um verdadeiro coringa: pode funcionar como fila (FIFO), como pilha (LIFO) e como híbrido.

Métodos principais da interface Deque

Método O que faz Exemplo de uso
addFirst(e)
Adicionar no início
ochered.addFirst("A")
addLast(e)
Adicionar no fim
ochered.addLast("B")
removeFirst()
Remover e retornar do início
ochered.removeFirst()
removeLast()
Remover e retornar do fim
ochered.removeLast()
peekFirst()
Olhar o início (sem remover)
ochered.peekFirst()
peekLast()
Olhar o fim (sem remover)
ochered.peekLast()
offerFirst(e)
Adicionar no início (sem exceção)
ochered.offerFirst("C")
offerLast(e)
Adicionar no fim (sem exceção)
ochered.offerLast("D")

Exemplo: Deque como fila e como pilha

import java.util.*;

public class DequeDemo {
    public static void main(String[] args) {
        Deque<String> deque = new ArrayDeque<>();

        // Usando como fila (FIFO)
        deque.offerLast("A");
        deque.offerLast("B");
        deque.offerLast("C");
        System.out.println("Fila (FIFO):");
        while (!deque.isEmpty()) {
            System.out.println(deque.pollFirst());
        }

        // Usando como pilha (LIFO)
        deque.offerLast("1");
        deque.offerLast("2");
        deque.offerLast("3");
        System.out.println("Pilha (LIFO):");
        while (!deque.isEmpty()) {
            System.out.println(deque.pollLast());
        }
    }
}

Saída:

Fila (FIFO):
A
B
C
Pilha (LIFO):
3
2
1

Por que ArrayDeque?

ArrayDeque é uma implementação Deque baseada em array, rápida e compacta. Para pilha e fila, ela costuma ser mais rápida e confiável do que a antiga Stack, e não tem tamanho fixo (limitada apenas pela memória).

3. Stack: pilha — último a entrar, primeiro a sair (LIFO)

A pilha é uma coleção segundo o princípio LIFO: removemos o topo sendo o último elemento adicionado. Em programação, a pilha é útil para histórico de ações (undo), travessia de estruturas recursivas (árvores/grafos), avaliação de expressões etc.

Classe Stack (e por que não usá-la)

Em Java existe a classe Stack, que herda da obsoleta Vector. Hoje não se recomenda usá-la em novos projetos. Prefira Deque/ArrayDeque.

Métodos de pilha (Deque)

Método O que faz
push(e)
Colocar o elemento no topo da pilha
pop()
Remover e retornar o elemento do topo
peek()
Olhar o elemento do topo

Atenção: em Deque essas operações correspondem aos métodos addFirst/removeFirst/peekFirst, mas por compatibilidade também existem os nomes “de pilha” push/pop/peek.

Exemplo: pilha com ArrayDeque

import java.util.*;

public class StackDemo {
    public static void main(String[] args) {
        Deque<String> stack = new ArrayDeque<>();
        stack.push("Primeiro");
        stack.push("Segundo");
        stack.push("Terceiro");

        while (!stack.isEmpty()) {
            System.out.println(stack.pop());
        }
    }
}

Saída:

Terceiro
Segundo
Primeiro

Por que não Stack?

  • Stack é sincronizada (mais lenta) e herda a obsoleta Vector.
  • ArrayDeque costuma ser mais rápida e compacta, não bloqueia threads.
  • Se você vir Stack em código novo — geralmente é candidata a substituição por ArrayDeque.

4. Quando usar o quê

Estrutura Princípio Onde usar Exemplo de implementação
Queue FIFO Fila de tarefas, processamento de eventos, impressão, filas de clientes
LinkedList, ArrayDeque, PriorityQueue
Stack LIFO Undo/redo, recursão, parsers, travessia de árvores
ArrayDeque
Deque FIFO/LIFO Buffers, palíndromos, filas de duas pontas, tarefas gerais
ArrayDeque, LinkedList

Exemplos do dia a dia:

  • Fila no banco — Queue.
  • Histórico de ações no editor — Stack.
  • Fila de ônibus, entrada/saída por ambas as pontas — Deque.

5. Exemplos de código: implementando fila e pilha em um miniaplicativo

Exemplo 1: fila de impressão de documentos

import java.util.*;

public class PrintQueueApp {
    public static void main(String[] args) {
        Queue<String> printQueue = new ArrayDeque<>();
        printQueue.offer("Documento1.pdf");
        printQueue.offer("Documento2.docx");
        printQueue.offer("Documento3.xls");

        while (!printQueue.isEmpty()) {
            String doc = printQueue.poll();
            System.out.println("Imprimindo: " + doc);
        }
    }
}

Exemplo 2: pilha de desfazer ações (undo)

import java.util.*;

public class UndoStackApp {
    public static void main(String[] args) {
        Deque<String> undoStack = new ArrayDeque<>();
        undoStack.push("Inserção de texto");
        undoStack.push("Alteração de cor");
        undoStack.push("Exclusão de imagem");

        System.out.println("Última ação: " + undoStack.peek()); // Exclusão de imagem

        while (!undoStack.isEmpty()) {
            System.out.println("Desfazer: " + undoStack.pop());
        }
    }
}

Exemplo 3: fila de duas pontas

import java.util.*;

public class DequeApp {
    public static void main(String[] args) {
        Deque<String> deque = new ArrayDeque<>();
        deque.addFirst("A");
        deque.addLast("B");
        deque.addFirst("C");
        deque.addLast("D");

        System.out.println("Removendo do início: " + deque.removeFirst()); // C
        System.out.println("Removendo do fim: " + deque.removeLast());   // D
        System.out.println("Restou: " + deque); // [A, B]
    }
}

6. Particularidades de implementação e nuances

  • ArrayDeque — a implementação de fila/pilha mais rápida e versátil para a maioria das tarefas.
  • LinkedList — também implementa Deque; pode ser útil, mas para filas curtas geralmente é mais lento que ArrayDeque.
  • PriorityQueue — fila por prioridade: a ordem é determinada pela prioridade (natural ou via Comparator), não é uma fila FIFO comum.
  • Stack — obsoleta e sincronizada; em novos projetos, prefira ArrayDeque.
  • Deque é conveniente por permitir trabalhar tanto com o início quanto com o fim da estrutura, cobrindo cenários de filas e pilhas com uma única abstração.

7. Erros típicos ao trabalhar com filas e pilhas

Erro nº 1: Usar Stack em vez de Deque.
Muitos iniciantes veem a classe Stack e a escolhem “pelo nome”. Em projetos modernos, em vez dela usa-se ArrayDeque (ou LinkedList) com os métodos push/pop.

Erro nº 2: Quebrar o princípio de funcionamento da estrutura.
Tentam acessar elementos da fila/pilha por índice, por exemplo queue.get(0) ou stack.get(0). Não pode — use os métodos apropriados de filas e pilhas (peek, poll, pop etc.).

Erro nº 3: Usar remove()/element()/add() sem verificação.
Os métodos remove, element, add podem lançar exceção quando a estrutura está vazia/cheia. É mais seguro usar os “suaves” offer, poll, peek, que retornam valores especiais.

Erro nº 4: Usar ArrayDeque com elementos null.
ArrayDeque não permite null. Tentar adicionar null causará NullPointerException.

Erro nº 5: Usar PriorityQueue como uma fila comum.
Em PriorityQueue, a ordem é determinada por prioridades (naturais ou definidas via Comparator). Para um FIFO estrito, use ArrayDeque ou LinkedList.

Erro nº 6: Modificar a fila/pilha durante um for-each.
Remover elementos da coleção durante o for-each pode levar a ConcurrentModificationException. Para remoção, use o iterador ou métodos poll/pop em loop, como mostrado nos exemplos.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION