J'ai besoin d'une structure de données Stack
pour mon cas d'utilisation. Je devrais être capable d'insérer des éléments dans la structure de données et je veux seulement 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 devraient être utilisé 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 devrais-je préférer Deque
à Stack
ici?
P.S: Le javadoc de Deque dit:
Deques peut également être utilisé comme pile LIFO (dernier entré, premier sorti). Ce l'interface doit être utilisée de préférence à la classe héritée Stack.
D'une part, c'est plus raisonnable en termes d'héritage. Le fait que Stack
prolonge Vector
est vraiment étrange, à mon avis. Au début de Java, l'héritage était surexploité IMO - Properties
étant un autre exemple.
Pour moi, le mot crucial dans la documentation que vous avez citée est cohérent . Deque
expose un ensemble d'opérations qui consiste à extraire/ajouter/supprimer des éléments au début ou à la fin d'une collection, à effectuer une itération, etc. - et c'est tout. Il n'y a délibérément aucun moyen d'accéder à un élément par position, ce que Stack
expose car c'est une sous-classe de Vector
.
Oh, et Stack
n'a pas d'interface. Si vous savez que vous avez besoin d'opérations Stack
, vous vous engagez dans une classe concrète spécifique, ce qui n'est généralement pas une bonne idée.
Voici mon interprétation de l'incohérence mentionnée dans la description de la classe Stack.
Si vous examinez les implémentations générales ici -, vous constaterez qu'il existe une approche cohérente pour la mise en œuvre de set, map et list.
Pour set et map, 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 tel que Set<String> set = new HashSet<String>();
see raisons ici .
Mais la classe Stack: 1) n’a pas sa propre interface; 2) est une sous-classe de la classe Vector - 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).
Pour moi, ce point spécifique manquait: Stack est Threadsafe car il est dérivé de Vector, alors que les implémentations les plus déques ne le sont pas, et donc plus rapidement si vous ne l’utilisez que dans un seul thread.
Une raison de plus pour utiliser Dequeue au lieu de pile est que Dequeue a la possibilité d'utiliser les flux convertis en liste en maintenant le concept LIFO appliqué, contrairement à la pile.
Stack<Integer> stack = new Stack<>();
Deque<Integer> deque = new ArrayDeque<>();
stack.Push(1);//1 is the top
deque.Push(1)//1 is the top
stack.Push(2);//2 is the top
deque.Push(2);//2 is the top
List<Integer> list1 = strack.stream().collect(Collectors.toList());//[1,2]
List<Integer> list2 = deque.stream().collect(Collectors.toList());//[2,1]
La performance pourrait être une raison. Un algorithme que j'ai utilisé est passé de 7,6 minutes à 1,5 minute en remplaçant simplement Stack par Deque.