W3docs

Interfaz Deque de Java

Operaciones de cola de doble extremo en Java con la interfaz Deque: addFirst, addLast, pollFirst, pollLast.

Deque<E> — pronunciado "deck," abreviación de double-ended queue (cola de doble extremo) — es Queue<E> con un segundo extremo. Donde una Queue solo permite eliminar desde la cabeza, una Deque permite insertar, eliminar y examinar en ambos extremos: la cabeza y la cola. Esa única capacidad adicional es suficiente para hacer de Deque el contrato detrás de dos abstracciones completamente diferentes: es una cola, es una pila, y el JDK la recomienda como la opción predeterminada para ambas.

Dos extremos × tres operaciones × dos estilos de error

La interfaz parece intimidante al principio porque cada operación aparece en doce formas: cabeza vs cola, insertar vs eliminar vs examinar, lanza excepción vs devuelve valor especial. Pero es simplemente la cuadrícula 3×2 de Queue extendida a dos extremos:

OperaciónPrimero (cabeza) — lanzaPrimero (cabeza) — valor especialÚltimo (cola) — lanzaÚltimo (cola) — valor especial
InsertaraddFirst(e)offerFirst(e)addLast(e)offerLast(e)
EliminarremoveFirst()pollFirst()removeLast()pollLast()
ExaminargetFirst()peekFirst()getLast()peekLast()

La columna "lanza" es la que se llama cuando una deque vacía/llena en ese punto sería un error. La columna "valor especial" es la que se llama cuando el estado vacío es esperado y se desea comprobar en una condición de bucle.

El mapeo de cola

Deque extiende Queue, por lo que una Deque es una Queue. Los métodos heredados son alias de las variantes de cabeza a cola:

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

Insertar al final, eliminar desde la cabeza: esa es la disciplina FIFO que una Queue ya proporciona, simplemente escrita con los nombres explícitos de cada extremo.

El mapeo de pila

Deque también define tres métodos "pila" que actúan sobre la cabeza:

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

Apilar y desapilar: disciplina LIFO, misma cabeza, extremo opuesto al insertar/eliminar del mapeo de cola. Por eso el capítulo de Stack te dirige aquí: la forma moderna de escribir una pila en Java es Deque<E> stack = new ArrayDeque<>(); y llamar a push / pop / peek.

La regla: null no está permitido

Al igual que Queue, el contrato de Deque reserva null como el centinela de "vacío" para pollFirst, pollLast, peekFirst, peekLast. Por ello, cada Deque de propósito general en el JDK rechaza los elementos null con NullPointerException al insertar. La única excepción es LinkedList, que permite null por razones históricas — y hereda toda la ambigüedad que eso conlleva. No hagas eso.

Iteración e iteración inversa

Una Deque tiene dos iteradores por convención:

  • iterator() recorre de cabeza a cola — el orden en que se llamaría pollFirst repetidamente.
  • descendingIterator() recorre de cola a cabeza — el orden en que se llamaría pollLast repetidamente.

Ambos son típicamente fail-fast: mutar la deque desde fuera del iterador mientras se itera lanza ConcurrentModificationException. Usa Iterator.remove() o removeIf si necesitas mutar durante un recorrido.

Elegir una implementación

En código monohilo hay esencialmente dos opciones:

  • ArrayDeque — la opción predeterminada. Array circular, O(1) en ambos extremos, sin asignación de nodos por elemento, amigable con la caché. Rechaza null. Implementa Deque y Queue.
  • LinkedList — nodos doblemente enlazados. También implementa List, por lo que cada elemento obtiene un nodo con punteros prev/next. Más lenta en ambos extremos que ArrayDeque y usa más memoria. Elígela solo si realmente necesitas semántica de Deque y List en el mismo objeto.

Para código concurrente (tratado más adelante en la parte de concurrencia del libro):

  • ConcurrentLinkedDeque — sin bloqueos, sin límite.
  • LinkedBlockingDeque — opcionalmente acotada, bloqueante — la versión que se usaría para construir una cola de robo de trabajo o un productor/consumidor con contrapresión en cualquier extremo.

Un ejemplo completo: cola, pila y verificación de palíndromo en una sola deque

El programa siguiente utiliza un ArrayDeque como cola FIFO, otro como pila LIFO y un tercero para comprobar si una frase es un palíndromo alimentando ambos extremos y comparando. La idea es que la misma interfaz, e incluso la misma clase, desempeña los tres roles.

java— editable, runs on the server

Lo que muestra esta ejecución:

  • La misma clase cumple los roles de cola y pila sin renombrar ningún método más allá de qué extremo se direcciona.
  • Los métodos de "valor de retorno especial" producen silenciosamente null cuando están vacíos; los métodos de "lanza" generan NoSuchElementException. Elige según si el estado vacío es esperado o un error.
  • La comprobación de palíndromo utiliza ambos extremos en el mismo buclepollFirst y pollLast juntos. Ese es el patrón de acceso que solo una Deque ofrece de forma eficiente.

Qué sigue

El capítulo de Deque cierra la parte del framework orientada a colas. La otra gran abstracción en Collection es la que rechaza duplicados: un Set es una Collection con el contrato de unicidad incorporado. Lo veremos a continuación.

Práctica

Práctica
Quieres una pila LIFO en código Java moderno. ¿Qué línea coincide con la recomendación del JDK?
Quieres una pila LIFO en código Java moderno. ¿Qué línea coincide con la recomendación del JDK?
Was this page helpful?