Necesito una Stack
estructura de datos para mi caso de uso. Debería poder insertar elementos en la estructura de datos y solo quiero recuperar el último elemento de la Pila. El JavaDoc para Stack dice:
La interfaz Deque y sus implementaciones proporcionan un conjunto más completo y coherente de operaciones de pila LIFO, que deben utilizarse con preferencia a esta clase. Por ejemplo:
Deque<Integer> stack = new ArrayDeque<>();
Definitivamente no quiero un comportamiento sincronizado aquí, ya que utilizaré esta estructura de datos local para un método. Aparte de esto, ¿por qué debería preferir Deque
por Stack
aquí?
PD: El javadoc de Deque dice:
Los Deques también se pueden usar como pilas LIFO (último en entrar, primero en salir). Esta interfaz debe usarse con preferencia a la clase de pila heredada.
fuente
Respuestas:
Por un lado, es más sensible en términos de herencia. El hecho de que se
Stack
extiendeVector
es realmente extraño, en mi opinión. Al principio de Java, la herencia se usó en exceso en la OMI,Properties
siendo otro ejemplo.Para mí, la palabra crucial en los documentos que citó es consistente .
Deque
expone un conjunto de operaciones que se trata de poder recuperar / agregar / eliminar elementos desde el inicio o el final de una colección, iterar, etc., y eso es todo. Deliberadamente, no hay forma de acceder a un elemento por posición, lo queStack
expone porque es una subclase deVector
.Ah, y tampoco
Stack
tiene interfaz, por lo que si sabes que necesitasStack
operaciones, terminas comprometiéndote con una clase concreta específica, que generalmente no es una buena idea.También como se señala en los comentarios,
Stack
yDeque
tienen órdenes de iteración inversa:que también se explica en los JavaDocs para Deque.iterator () :
fuente
LinkedList
, peroArrayDequeue
(a menudo) será más rápido. Si desea un comportamiento de pila, puede usarloStack
peroArrayDeque
(a menudo) será más rápido.Stack
tiene el problema de exposición de representantes, pero si quiero una estructura de datos de la pila, me gustaría poder llamar a métodos como push, pop y peek, y no a las cosas que tienen que hacer con el otro extremo de la pila.Aquí está mi interpretación de la inconsistencia mencionada en la descripción de la clase Stack.
Si observa las implementaciones de propósito general aquí , verá que hay un enfoque coherente para la implementación del conjunto, el mapa y la lista.
Para set y map tenemos 2 implementaciones estándar con mapas hash y árboles. El primero se usa más y el segundo se usa cuando necesitamos una estructura ordenada (y también implementa su propia interfaz: SortedSet u SortedMap).
Podemos usar el estilo preferido de declaración como
Set<String> set = new HashSet<String>();
ver razones aquí .Pero la clase Stack: 1) no tiene su propia interfaz; 2) es una subclase de la clase Vector, que se basa en una matriz redimensionable; Entonces, ¿dónde está la implementación de la lista vinculada de la pila?
En la interfaz Deque no tenemos tales problemas, incluidas dos implementaciones (matriz redimensionable - ArrayDeque; lista enlazada - LinkedList).
fuente
Una razón más para usar Dequeue sobre Stack es que Dequeue tiene la capacidad de usar streams convert to list y mantener el concepto LIFO aplicado mientras que Stack no.
fuente
Aquí hay algunas razones por las que Deque es mejor que Stack:
Diseño orientado a objetos: herencia, abstracción, clases e interfaces: Stack es una clase, Deque es una interfaz. Solo se puede extender una clase, mientras que una sola clase en Java puede implementar cualquier cantidad de interfaces (herencia de tipo múltiple). El uso de la interfaz Deque elimina la dependencia de la clase Stack concreta y sus antepasados y le brinda más flexibilidad, por ejemplo, la libertad de extender una clase diferente o intercambiar diferentes implementaciones de Deque (como LinkedList, ArrayDeque).
Inconsistencia: Stack extiende la clase Vector, que le permite acceder al elemento por índice. Esto es inconsistente con lo que realmente debería hacer una Pila, por lo que se prefiere la interfaz Deque (no permite tales operaciones): sus operaciones permitidas son consistentes con lo que una estructura de datos FIFO o LIFO debería permitir.
Rendimiento: la clase de Vector que Stack extiende es básicamente la versión "segura para subprocesos" de una ArrayList. Las sincronizaciones pueden causar un impacto significativo en el rendimiento de su aplicación. Además, extender otras clases con funcionalidad innecesaria (como se menciona en el n. ° 2) hincha sus objetos, lo que puede costar una gran cantidad de memoria adicional y sobrecarga de rendimiento.
fuente
Para mí, este punto específico faltaba: Stack es Threadsafe ya que se deriva de Vector, mientras que las implementaciones más antiguas no lo son, y por lo tanto más rápido si solo lo usa en un solo hilo.
fuente
El rendimiento podría ser una razón. Un algoritmo que utilicé pasó de 7.6 minutos a 1.5 minutos simplemente reemplazando Stack con Deque.
fuente
Deque se utiliza en una situación en la que desea recuperar elementos de la cabeza y la cola. Si quieres una pila simple, no hay necesidad de ir a una deque.
fuente