2015-01-15 4 views
12

Ich habe eine Situation, in der ich eine Datenbank lese und eine List<String> zurückschicke, wo jeder String ausgewählt und der Liste nach einigen Kriterien hinzugefügt wird. Die Methodensignatur ist:Ist es sicher für eine Methode, einen Stream <T> zurückzugeben?

public List<String> myMethod(String query, int limit) 

Der zweite Parameter eine obere von der Größe der zurückgegebenen Liste (Einstellung limit=-1 jede Größenbeschränkung wird entfernen) gebunden enthält. Um zu vermeiden, dass diese Methode speicherintensiv wird, habe ich eine entsprechende Methode geschrieben, die anstelle einer Liste Stream<String> zurückgibt. (Hinweis: Ich brauche keinen direkten Zugriff auf die zurückgegebenen Elemente oder jede andere Liste spezifische Funktionalität.)

Allerdings bin ich ein bisschen skeptisch, was eine Stream<> Rückkehr, zumal das Verfahren öffentlich ist. Ist es sicher, eine öffentliche Methode zu haben, die eine Stream<> in Java zurückgibt?

+1

Unter bestimmten Umständen kann es einfacher und klarer sein, einen Iterable/Iterator zurückzugeben. Ich baue oft einen 'Iterator ' in meinem Code. Einen 'Stream' aus einem' Iterator' zu machen ist ziemlich [einfach] (http://stackoverflow.com/q/21956515/823393). – OldCurmudgeon

+2

@OldCurmudgeon Wenn Sie 'Stream' zurückgeben, erhalten Sie' Iterator' fast kostenlos ('stream.iterator()'). –

+0

@Marko - Einverstanden - aber Sie sind immer noch abwärtskompatibel mit Java 7 und früher, wenn Sie dann einen einfachen Adapter anbieten, um den 'Iterator' in Java 8 zu streamen. – OldCurmudgeon

Antwort

12

Nicht nur ist es sicher, es ist recommended von der Chef-Java-Architekt.

Insbesondere wenn Ihre Daten I/O-basiert sind und somit zum Zeitpunkt myMethod noch nicht im Speicher abgelegt sind, wäre es sehr ratsam, anstelle einer Liste einen Stream zurückzugeben. Der Client muss möglicherweise nur einen Teil davon konsumieren oder in einige Daten fester Größe aggregieren. Somit haben Sie die Möglichkeit von O (n) Speicherbedarf zu O (1) zu gelangen.

Beachten Sie, dass, wenn die Parallelisierung auch eine interessante Idee für Ihren Anwendungsfall ist, Sie einen benutzerdefinierten Spliterator verwenden sollten, dessen Aufteilungsrichtlinie an die sequenzielle Art von E/A-Datenquellen angepasst ist. In diesem Fall kann ich a blog post of mine empfehlen, das einen solchen Spliterator darstellt.

+1

Vielen Dank für den Link zu Brian Goetz 'Antwort. Ich habe nur noch einen Zweifel an der Sicherheit: Die Rückgabe eines 'Stream <>' in einer öffentlichen Methode bedeutet, dass ich nicht sicherstellen kann, dass sie geschlossen wird. Ich habe bemerkt, dass [Javadoc] (http://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html) sagt: "Fast alle Stream-Instanzen müssen nicht wirklich geschlossen werden verwenden ", konnte aber nicht mehr Details zu diesem verdächtigen Wort" fast "finden. –

+2

@ChthonicProject Nun, es ist sehr einfach: Wenn Ihr Stream von einer I/O-Ressource unterstützt wird, dann muss er definitiv geschlossen werden. Dies ist eine Entscheidung, die Sie treffen müssen - eifrig alles auf den Heap kopieren, die I/O-Ressource freigeben oder einen Stream haben, der geschlossen werden muss. Aber ich würde für das Folgende argumentieren: Es ist trivial, eine Methode zu haben, die einen I/O-gestützten Strom sicher in eine On-Heap-Liste umwandelt; die andere Richtung ist unmöglich. Sie fügen also nichts als Flexibilität hinzu, indem Sie mit dem Stream arbeiten. –

+1

Habe den wichtigen Satz, der im selben Absatz im Javadoc folgt, nicht bemerkt. Teilen Sie es hier, um die Freude zu verbreiten: "* Wenn ein Stream schließen muss, kann es in einer Try-with-Resources-Anweisung als Ressource deklariert werden. * Das zusammen mit Ihrem Kommentar (und natürlich der Hauptantwort), beendet alle meine Zweifel und Zögern. –