J'ai besoin d'une Stack
structure de données pour mon cas d'utilisation. Je devrais pouvoir pousser des éléments dans la structure de données et je souhaite uniquement récupérer le dernier élément de la pile. Le JavaDoc for Stack dit:
Un ensemble plus complet et cohérent d'opérations de pile LIFO est fourni par l'interface Deque et ses implémentations, qui doivent être utilisées de préférence à cette classe. Par exemple:
Deque<Integer> stack = new ArrayDeque<>();
Je ne veux certainement pas de comportement synchronisé ici car j'utiliserai cette structure de données locale à une méthode. En dehors de cela pourquoi je préfère Deque
plus Stack
ici?
PS: Le javadoc de Deque dit:
Les Deques peuvent également être utilisés comme piles LIFO (Last-In-First-Out). Cette interface doit être utilisée de préférence à l'ancienne classe Stack.
la source
Réponses:
D'une part, c'est plus sensé en termes d'héritage. Le fait que cela se
Stack
prolongeVector
est vraiment étrange, à mon avis. Au début de Java, l'héritage était surutilisé à l'OMI -Properties
un autre exemple.Pour moi, le mot crucial dans les documents que vous avez cités est cohérent .
Deque
expose un ensemble d'opérations qui consiste à pouvoir récupérer / ajouter / supprimer des éléments au début ou à la fin d'une collection, itérer, etc. - et c'est tout. Il n'y a délibérément aucun moyen d'accéder à un élément par position, ce quiStack
expose parce que c'est une sous-classe deVector
.Oh, et
Stack
n'a pas non plus d'interface, donc si vous savez que vous avez besoin d'Stack
opérations, vous finissez par vous engager dans une classe concrète spécifique, ce qui n'est généralement pas une bonne idée.Également comme indiqué dans les commentaires,
Stack
etDeque
ont des ordres d'itération inversés:qui est également expliqué dans les JavaDocs pour Deque.iterator () :
la source
LinkedList
, mais ceArrayDequeue
sera (souvent) plus rapide. Si vous voulez un comportement de pile, vous pouvez utiliserStack
maisArrayDeque
sera (souvent) plus rapide.Stack
a le problème d'exposition des représentants, mais si je veux une structure de données de pile, j'aimerais pouvoir appeler des méthodes comme push, pop et peek, et pas les choses doivent faire avec l'autre extrémité de la pile.Voici mon interprétation de l'incohérence mentionnée dans la description de la classe Stack.
Si vous regardez les implémentations à usage général ici , vous verrez qu'il existe une approche cohérente de la mise en œuvre de l'ensemble, de la carte et de la liste.
Pour l'ensemble et la carte, nous avons 2 implémentations standard avec des cartes de hachage et des arbres. Le premier est le plus utilisé et le second est utilisé lorsque nous avons besoin d'une structure ordonnée (et il implémente également sa propre interface - SortedSet ou SortedMap).
Nous pouvons utiliser le style préféré de déclaration comme
Set<String> set = new HashSet<String>();
voir les raisons ici .Mais la classe Stack: 1) n'a pas sa propre interface; 2) est une sous-classe de la classe Vector - qui est basée sur un tableau redimensionnable; Alors, où est la mise en œuvre de la liste chaînée de la pile?
Dans l'interface Deque, nous n'avons pas de tels problèmes, y compris deux implémentations (tableau redimensionnable - ArrayDeque; liste liée - LinkedList).
la source
Une autre raison d'utiliser Dequeue sur Stack est que Dequeue a la possibilité d'utiliser des flux convertis en liste tout en conservant le concept LIFO appliqué alors que Stack ne le fait pas.
la source
Voici quelques raisons pour lesquelles Deque est meilleur que Stack:
Conception orientée objet - Héritage, abstraction, classes et interfaces: Stack est une classe, Deque est une interface. Une seule classe peut être étendue, alors que n'importe quel nombre d'interfaces peut être implémenté par une seule classe en Java (héritage multiple de type). L'utilisation de l'interface Deque supprime la dépendance sur la classe Stack concrète et ses ancêtres et vous donne plus de flexibilité, par exemple la liberté d'étendre une classe différente ou d'échanger différentes implémentations de Deque (comme LinkedList, ArrayDeque).
Incohérence: Stack étend la classe Vector, qui vous permet d'accéder élément par index. Ceci est incompatible avec ce qu'une pile devrait réellement faire, c'est pourquoi l'interface Deque est préférée (elle ne permet pas de telles opérations) - ses opérations autorisées sont cohérentes avec ce qu'une structure de données FIFO ou LIFO devrait permettre.
Performances: La classe Vector que Stack étend est essentiellement la version "thread-safe" d'un ArrayList. Les synchronisations peuvent potentiellement entraîner une baisse significative des performances de votre application. En outre, l'extension d'autres classes avec des fonctionnalités inutiles (comme mentionné dans # 2) gonfle vos objets, ce qui peut coûter beaucoup de mémoire supplémentaire et de surcharge de performances.
la source
Pour moi, ce point spécifique manquait: Stack est Threadsafe car il est dérivé de Vector, alors que les implémentations les plus deque ne le sont pas, et donc plus rapide si vous ne l'utilisez que dans un seul thread.
la source
La performance pourrait être une raison. Un algorithme que j'ai utilisé est passé de 7,6 minutes à 1,5 minutes en remplaçant simplement Stack par Deque.
la source
Deque est utilisé dans une situation où vous souhaitez récupérer des éléments à la fois de la tête et de la queue. Si vous voulez une pile simple, il n'est pas nécessaire de faire un deque.
la source