2017-03-24 9 views
1

Stream<T>Spliterator<T>によって提供される内部反復アプローチに基づいており、次にboolean tryAdvance(Consumer<? super T> action)実装で反復を委任します。シンプルなそれを置く:関数からのストリームを作成する最も簡単な方法

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

だから、私はFunction<Consumer<T>, Boolean>からStream<T>を作成することを可能にするユーティリティのいくつかの並べ替えを持っていると思います。 Function<Consumer<T>, Boolean>boolean tryAdvance(Consumer<T>)と同じ記述子を持ちます。つまり、Consumer<T> -> Booleanです。

私は、このような(@ shmoselの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); 
} 

これは私がその実現を達成するために見出される最も簡潔な方法です。しかし、私はまだ匿名の内部クラスの使用が嫌いです。最も簡単な選択肢はありますか?

+1

私はそれが可能かもしれないかどうかは知っていませんが、その要件の理由はありますか?おそらくあなたが望むものは、別の方法で達成されるかもしれません。 –

+0

@JoãoRebeloオリジナルのStream APIでは 'takeWhile'、' zip'などのように多くのクエリメソッドが用意されていますので、DIYや欠けているメソッドを追加したいときは 'Iterator'や'Spliterator'を呼び出して' Stream'に戻します –

+0

[述語でストリームを制限する](http://stackoverflow.com/q/20746429/1140754)または[ストリームの偶数行をスキップする方法](http://stackoverflow.com/q/30170089/1140754) –

答えて

3

機能を受け取る組み込み機能がないため、タイプを作成する方法はありませんが、内部クラスである必要はありません。例えば。以下のように使用することができます

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

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

しかし、今、あなたはカスタム中間の操作を実装を目指していることを明らかにしたことは、上記のソリューションは適していません。専用のトップレベルクラスである内部クラスに代わる他の方法を使用する方が良いかもしれません。

これらの操作のほとんどは、前述の例のように、どちらかを実行するか、キャリー状態を指定するか、単一の関数を使用して表現できない特性またはより洗練された見積もりサイズを指定する必要があります。

+0

Re:カスタム中間演算の実装:Spliteratorのメソッドを実装するラムダを受け入れる静的メソッドを使用して、Spliterator、la Collector :: ofを実装することができます。しかし、lambda Collector :: of-styleを設計し、結果のSpliteratorを参照する能力がない場合や、Spliteratorインスタンスを最初のパラメータとして使用してlambdaを設計する方が良いかどうかはわかりません。 – srborlongan

+2

@ srborlongan:私はすでにそれについて考えました。ステートレスオブジェクトの場合、 'BiPredicate 、Consumer >'で十分ですが、状態オブジェクトの受け渡しを許可するには、3つのパラメータ、つまりカスタムインタフェースを必要とします。関数がスプライテータインスタンスを取得するようにすると、パラメータが2に減少しますが、関数が多くの一般的な作業を繰り返すことを意味します。 – Holger

+0

合意。私はカスタムインターフェイスソリューションを使用しましたが、それは非常に上手です。必ずしも最初の解決策ではありませんが、ステートレスなラムダがその環境下で作成する方が簡単なため、一般的には優れています。 – srborlongan

関連する問題