2015-05-22 5 views
15

Ich habe eine Methode, die jedes Mal ein Objekt generiert, wenn ich es ausführe, und ich muss die Reihenfolge umkehren, mit der ich sie bekomme. Also dachte ich, der natürliche Weg wäre ein Stack, da es LIFO ist.Stack mit der Java 8 Collection Streaming-API

Allerdings scheint das Java Stack nicht gut mit der neuen Java 8 Streaming API zu spielen.

Wenn ich dies tun:

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); 

Der Ausgang ich erhalte, ist:

Collected: [A, B, C] 

Warum ist sie nicht in der erwarteten LIFO, um den Strom outputing? Ist dies der richtige Weg, um alle Artikel vom Stapel zu einer Liste in der richtigen (LIFO) Reihenfolge zu spülen?

+0

Ich erwarte, dass es ist, weil Stapel Vector erstreckt (die die ursprüngliche Auftrag unterhält; pop gibt Ihnen die ** ** letzte Objekt in der Stapel). Erhalten Sie das gleiche Ergebnis mit einem Deque? ArrayDeque zum Beispiel schiebt und springt von der Vorderseite, so dass es Ihnen die gewünschte Reihenfolge geben sollte. – azurefrog

+0

'Deque' (und seine implementierenden Klassen) haben nicht einmal eine' stream() 'Methode. Die Frage ist nicht, ob ich das umgehen kann (ich kann natürlich meine eigene Schleife schreiben). Warum würde Stack die stream-Methode anbieten und sie falsch streamen, wenn man bei der Wahl der verwendeten Sammlung eine LIFO-Bestellung erwarten würde? – jbx

+1

Nach der [ArrayDeque API] (https://docs.oracle.com/javase/8/docs/api/java/util/ArrayDeque.html), hat es die gleiche 'stream()' Methode von java.util .Collection, die [Stack] (https://docs.oracle.com/javase/8/docs/api/java/util/Stack.html) tut. Ich habe jedoch Java 8 hier nicht, also kann ich es nicht testen. – azurefrog

Antwort

23

Wie bereits in den Kommentaren erwähnt, haben wir Deque Schnittstelle getestet, die bevorzugt werden sollte.

Aber ich gebe Ihnen den Grund, warum Stack nicht verwendet werden sollte.

Zunächst ist das Java Doc. der Stapel sagt selbst:

Ein vollständiger und konsistenter Satz von Stapeloperationen LIFO ist durch die Deque-Schnittstelle und deren Implementierungen zur Verfügung gestellt, die sollten zu dieser Klasse bevorzugt verwendet werden. Zum Beispiel:

Deque-Stack = neue ArrayDeque();

Siehe JavaDoc.

Also was ist das Problem mit der Stack Klasse.

Wie Martin Fowler bereits in seinem Buch Refactoring erwähnt: Das Design vorhandener Software verbessern am Refactoring Methode Vererbung mit Delegation ersetzen, ein Stapel sollte nicht von einem Vektor erben.

Eines der klassischen Beispiele für unangemessene Vererbung besteht darin, einen Stack zu einer Unterklasse von Vektor zu machen. Java 1.1 tut dies in seinen Dienstprogrammen (ungezogene Jungen!) [6, p. 288]

Stattdessen sollten sie Delegierung verwendet haben, wie im Bild unten, , die auch aus dem Buch ist.

Siehe auch hier: Replace Inheritance with Delegation

Replace Inheritance with Delegation

So aber warum ist das ein Problem:

Da der Stapel nur 5 Methoden:

  1. pop
  2. Push
  3. isEmpty
  4. Suche
  5. Größe

    size() und isEmpty() aus der Vector Klasse und die anderen Methoden aus den Vector nicht verwendet werden vererbt. Aber durch die Vererbung werden andere Methoden an die Klasse Stack weitergeleitet, was keinen Sinn ergibt.

Und Fowler sagt für dieses Problem:

Sie können mit der Lage und Nutzung Konvention leben zu sagen, dass obwohl es sich um eine Unterklasse ist, ist es nur ein Teil der übergeordneten Klasse Funktion. Aber das führt zu einem Code, der eine Sache sagt, wenn Ihre Absicht etwas anderes ist - eine Verwirrung, die Sie entfernen sollten.

Dies schadet der Interface Segregation Principle

die sagt:

KUNDEN, sollten Sie nicht abzuhängen UPON INTERFACES gezwungen werden, die sie tun NICHT.


Sie können den Code Quelle überprüfen der Vector und Stack Klasse und Sie werden sehen, dass die Stack-Klasse die spliterator Methode und die VectorSpliterator Innerclass von der Vector Klasse erben.

Diese Methode wird von der Schnittstelle Collection zur Impl. Verwendet. die Standard-Version der Stream-Methode:

default Stream<E> More ...stream() { 
    return StreamSupport.stream(spliterator(), false); 
} 

So vermeiden Sie einfach die Nutzung der Vector und Stack Klasse.

[6] Refactoring: Verbesserung der Gestaltung vorhandener Software Fowler, Martin Jahr 1997

+1

Danke für die detaillierte Erklärung. – jbx