Apilar utilizando la API de transmisión de la colección Java 8
java-8 java-stream (1)
Tengo un método que genera un objeto cada vez que lo ejecuto, y necesito revertir el orden con el que los estoy obteniendo. Así que pensé que la forma natural de hacerlo sería una Pila, ya que es LIFO.
Sin embargo, el Java Stack no parece funcionar bien con la nueva API de transmisión de Java 8.
Si hago esto:
Stack<String> stack = new Stack<String>();
stack.push("A");
stack.push("B");
stack.push("C");
List<String> list = stack.stream().collect(Collectors.toList());
System.out.println("Collected: " + list);
La salida que obtengo es:
Collected: [A, B, C]
¿Por qué no los está enviando en el orden LIFO esperado a la transmisión? ¿Es esta la forma correcta de eliminar todos los elementos de la pila a una lista en el orden correcto (LIFO)?
Como ya se mencionó en los comentarios, hemos probado la interfaz de Deque
, que debería ser la preferida.
Pero te daré la razón por la que Stack
no debería usarse.
Al principio, el doc. Java. de la pila se dice:
La interfaz de Deque y sus implementaciones proporcionan un conjunto más completo y consistente de operaciones de apilamiento LIFO, que se deben usar con preferencia a esta clase. Por ejemplo:
Deque stack = new ArrayDeque ();
Ver JavaDoc .
Entonces, ¿cuál es el problema con la clase Stack
.
Como Martin Fowler ya mencionó en su libro Refactoring: Mejorando el diseño de código existente en el método de refactoring Reemplazar la herencia con la delegación , una pila no debe heredar de un Vector.
Uno de los ejemplos clásicos de herencia inapropiada es hacer de una pila una subclase de vector. Java 1.1 hace esto en sus utilidades (¡muchachos traviesos!) [6, pág. 288]
En su lugar, deberían haber utilizado la delegación como en la imagen de abajo, que también es del libro.
Véase también aquí: Reemplazar la herencia con la delegación
Entonces, pero ¿por qué es esto un problema?
Porque la pila tiene solo 5 métodos:
- popular
- empujar
- esta vacio
- buscar
tamaño
size()
eisEmpty()
se heredan de la claseVector
y los otros métodos delVector
no se utilizan. Pero a través de la herencia, otros métodos se envían a la clase deStack
que no tiene sentido.
Y Fowler le dice a este problema:
Puedes vivir con la situación y usar la convención para decir que aunque es una subclase, está usando solo una parte de la función superclase. Pero eso da como resultado un código que dice una cosa cuando su intención es otra cosa: una confusión que debe eliminar.
Esto duele el principio de segregación de interfaz
que dice:
LOS CLIENTES NO DEBEN SER OBLIGADOS A DEPENDER DE LAS INTERFACES QUE NO UTILIZAN.
Puede consultar el código fuente de la clase Vector y Stack y verá que la clase Pila heredará el método del VectorSpliterator
y la VectorSpliterator
interna VectorSpliterator de la clase Vector
.
Este método es utilizado por la interfaz de la Collection
para implementar. la versión por defecto del método de flujo:
default Stream<E> More ...stream() {
return StreamSupport.stream(spliterator(), false);
}
Así que evite simplemente el uso de la clase Vector
y Stack
.
[6] Refactorización: Mejora del diseño del código existente Fowler, Martin año 1997