W3docs

Interface Deque do Java

Operações de fila de duas extremidades em Java com a interface Deque — addFirst, addLast, pollFirst, pollLast.

Deque<E> — pronunciado "deck," abreviação de double-ended queue (fila de duas extremidades) — é um Queue<E> com uma segunda extremidade. Enquanto uma Queue só permite remover da cabeça, uma Deque permite inserir, remover e examinar em ambas as extremidades, cabeça e cauda. Essa única capacidade extra é suficiente para tornar Deque o contrato por trás de duas abstrações completamente diferentes: é uma fila, é uma pilha, e o JDK a recomenda como padrão para ambas.

Duas extremidades × três operações × dois estilos de erro

A interface parece intimidadora no início porque cada operação aparece em doze formas — cabeça vs cauda, inserção vs remoção vs exame, lança exceção vs retorna valor especial. Mas é apenas a grade 3×2 do Queue estendida por duas extremidades:

OperaçãoPrimeira (cabeça) — lançaPrimeira (cabeça) — valor especialÚltima (cauda) — lançaÚltima (cauda) — valor especial
InserçãoaddFirst(e)offerFirst(e)addLast(e)offerLast(e)
RemoçãoremoveFirst()pollFirst()removeLast()pollLast()
ExamegetFirst()peekFirst()getLast()peekLast()

A coluna "lança" é a que você usa quando uma deque vazia/cheia naquele ponto seria um bug. A coluna "valor especial" é a que você usa quando o estado vazio é esperado e você quer testá-lo em uma condição de loop.

O mapeamento de fila

Deque estende Queue, portanto uma Deque é uma Queue. Os métodos herdados são aliases para as variantes de cabeça-a-cauda:

Método QueueEquivalente Deque
add(e) / offer(e)addLast(e) / offerLast(e)
remove() / poll()removeFirst() / pollFirst()
element() / peek()getFirst() / peekFirst()

Inserir na cauda, remover da cabeça — essa é a disciplina FIFO que um Queue já oferece, apenas escrita com os nomes explícitos de cada extremidade.

O mapeamento de pilha

Deque também define três métodos de "pilha" que atuam todos na cabeça:

Método de pilhaEquivalente Deque
push(e)addFirst(e)
pop()removeFirst()
peek()peekFirst()

Empilhar, desempilhar — disciplina LIFO, mesma cabeça, extremidade oposta da inserção/remoção em relação ao mapeamento de fila. É por isso que o capítulo sobre Stack indicou você aqui: a forma moderna de escrever uma pilha em Java é Deque<E> stack = new ArrayDeque<>(); e chamar push / pop / peek.

A regra: null não é permitido

Assim como Queue, o contrato de Deque reserva null como sentinela de "vazio" para pollFirst, pollLast, peekFirst, peekLast. Por isso, toda Deque de propósito geral no JDK rejeita elementos null com NullPointerException na inserção. A única exceção é LinkedList, que permite null por razões históricas — e herda toda a ambiguidade que isso implica. Não faça isso.

Iteração e iteração reversa

Uma Deque tem dois iteradores por convenção:

  • iterator() percorre de cabeça a cauda — a ordem em que você chamaria pollFirst repetidamente.
  • descendingIterator() percorre de cauda a cabeça — a ordem em que você chamaria pollLast repetidamente.

Ambos são tipicamente fail-fast: modificar a deque de fora do iterador durante a iteração lança ConcurrentModificationException. Use Iterator.remove() ou removeIf se precisar modificar durante uma travessia.

Escolhendo uma implementação

Em código de thread única, há essencialmente duas opções:

  • ArrayDeque — o padrão. Array circular, O(1) em ambas as extremidades, sem alocação de nó por elemento, amigável ao cache. Rejeita null. Implementa Deque e Queue.
  • LinkedList — nós duplamente encadeados. Também implementa List, então cada elemento recebe um nó com ponteiros prev/next. Mais lento em ambas as extremidades do que ArrayDeque e usa mais memória. Use-o apenas se você realmente precisar de semântica de Deque e List no mesmo objeto.

Para código concorrente (abordado mais adiante na parte de concorrência do livro):

  • ConcurrentLinkedDeque — sem bloqueio, ilimitado.
  • LinkedBlockingDeque — opcionalmente limitado, bloqueante — a versão que você usaria para construir uma fila de roubo de trabalho ou um produtor/consumidor com contrapressão em qualquer extremidade.

Exemplo prático: fila, pilha e verificação de palíndromo em uma deque

O programa abaixo usa um ArrayDeque como fila FIFO, outro como pilha LIFO e um terceiro para verificar se uma frase é um palíndromo, alimentando ambas as extremidades e comparando. O ponto é que a mesma interface, e até a mesma classe, desempenha os três papéis.

java— editable, runs on the server

O que essa execução demonstra:

  • A mesma classe desempenha os papéis de fila e pilha sem renomear nenhum método além de qual extremidade você acessa.
  • Os métodos de "retorno de valor especial" produzem silenciosamente null para o caso vazio; os métodos de "lança" levantam NoSuchElementException. Escolha com base em se o estado vazio é esperado ou é um bug.
  • A verificação de palíndromo usa ambas as extremidades no mesmo looppollFirst e pollLast juntos. Esse é o padrão de acesso que apenas uma Deque oferece com eficiência.

O que vem a seguir

O capítulo sobre Deque encerra o lado de filas do framework. A outra grande abstração em Collection é aquela que rejeita duplicatas: um Set é uma Collection com o contrato de unicidade embutido. Veremos isso a seguir.

Prática

Prática
Você quer uma pilha LIFO em código Java moderno. Qual linha corresponde à recomendação do JDK?
Você quer uma pilha LIFO em código Java moderno. Qual linha corresponde à recomendação do JDK?
Was this page helpful?