2017-03-24 3 views
1

Stream<T> basiert auf dem internen Iterationsansatz von Spliterator<T>, der wiederum die Iteration auf boolean tryAdvance(Consumer<? super T> action) Implementierung delegiert. Legen Sie es einfach:Einfachste Möglichkeit, einen Stream aus einer Funktion zu erstellen

Stream<T>---->Spliterator<T>---->boolean tryAdvance(Consumer<T>)

Also, ich möchte eine Art von Programm haben, die eine Stream<T> von einem Function<Consumer<T>, Boolean> erstellen können. Man beachte, dass Function<Consumer<T>, Boolean> den gleichen Deskriptor boolean tryAdvance(Consumer<T>), d. H. Consumer<T> -> Boolean, hat.

Ich bin für eine Hilfsfunktion wie (aktualisiert nach @ shmosel des comment):

static <T> Stream<T> stream(Predicate<Consumer<? super T>> moveNext) { 
    Spliterator<T> iter = new AbstractSpliterator<T>(Long.MAX_VALUE, 0) { 
     @Override 
     public boolean tryAdvance(Consumer<? super T> action) { 
      return moveNext.test(action); 
     } 
    }; 
    return StreamSupport.stream(iter, false); 
} 

Dies ist die prägnante Art und Weise, die ich, dass die Umsetzung erreichen gefunden. Dennoch mag ich den Gebrauch der anonymen inneren Klasse immer noch nicht. Gibt es eine einfachste Alternative?

+1

Ich weiß nicht, ob das möglich ist, aber gibt es einen Grund für diese Anforderung? Vielleicht, was du willst, kann man anders herum erreichen. –

+0

@ JoãoRebelo Es gibt viele Abfragemethoden, die nicht in der Original-Stream-API enthalten sind, wie 'takeWhile',' zip' usw. Wenn Sie also DIY erstellen und eine fehlende Methode hinzufügen wollen, müssen Sie über 'Iterator' oder 'Spliterator' und wandle es zurück in' Stream' –

+0

zB [Einen Stream durch ein Prädikat begrenzen] (http://stackoverflow.com/q/20746429/1140754) oder [Wie man gerade Zeilen eines Streams überspringt ] (http://stackoverflow.com/q/30170089/1140754) –

Antwort

3

Da es kein eingebautes Feature gibt, das eine Funktion akzeptiert, gibt es keine Möglichkeit, einen Typ zu erstellen, obwohl es keine innere Klasse sein muss. Z.B.

public interface SingleFuncStream<T> extends Spliterator<T> { 
    public static <T> Stream<T> stream(SingleFuncStream<T> f) { 
     return StreamSupport.stream(f, false); 
    } 
    @Override default public Spliterator<T> trySplit() { return null; } 
    @Override default public long estimateSize() { return Long.MAX_VALUE; } 
    @Override default public int characteristics() { return ORDERED; } 
} 

, die wie verwendet werden kann,

ListIterator<String> i = Arrays.asList("foo", "bar", "baz").listIterator(3); 
SingleFuncStream.<String>stream(c -> { 
    if(!i.hasPrevious()) return false; 
    c.accept(i.previous()); 
    return true; 
}).forEach(System.out::println); 

Aber jetzt, wo Sie geklärt haben, dass Sie benutzerdefinierte Zwischenoperationen bei der Durchführung der obigen Lösung ist nicht geeignet anstreben. Es könnte besser sein, die andere Alternative zu einer inneren Klasse, einer dedizierten obersten Klasse, zu verwenden.

Die meisten dieser Operationen, wie die von Ihnen erwähnten Beispiele, haben entweder einen Status oder müssen Eigenschaften oder eine komplexere Schätzgröße angeben, die Sie nicht mit einer einzigen Funktion ausdrücken können.

+0

Re: Implementieren benutzerdefinierter Zwischenoperationen: Eine statische Methode, die Lambdas akzeptiert, die die Methoden in Spliterator implementieren, kann verwendet werden, um den Spliterator zu implementieren, a la Collector :: of. Ich weiß jedoch nicht, ob es besser wäre, Lambdas Collector :: of-style zu entwerfen, ohne die Möglichkeit, den resultierenden Spliterator zu referenzieren, oder diese lambdas mit der Spliterator-Instanz als erstem Parameter zu entwerfen. – srborlongan

+2

@srborlongan: Ich habe schon darüber nachgedacht. Für zustandslose Ops wäre ein 'BiPredicate , Consumer >' ausreichend, aber wenn Sie ein Zustandsobjekt übergeben möchten, benötigen Sie eine Funktion mit drei Parametern, daher eine benutzerdefinierte Schnittstelle. Wenn die Funktionen die Spliterator-Instanz erfassen, werden die Parameter auf zwei reduziert, aber die Funktionen wiederholen sich häufig. – Holger

+0

Einverstanden.Ich habe die benutzerdefinierte Interface-Lösung verwendet, und es ist ganz in Ordnung. Nicht unbedingt die erste Lösung, die mir in den Sinn kommt, aber sie ist im Allgemeinen besser, schon allein deshalb, weil in diesem Milieu zustandslose Lambdas einfacher zu erstellen sind. – srborlongan

Verwandte Themen