ストリームをイテラブルにするにはどうすればよいですか?[重複]


8

Streamiterator()メソッドを継承してを生成しIteratorます。

しかし、私はではIterableなくが必要Iteratorです。

たとえば、次の文字列があるとします。

String input = "this\n" +
        "that\n" +
        "the_other";

…文字列のこれらの部分をIterable特定のライブラリに渡す必要があります。を呼び出すinput.lines()と、Stream。私はそれを作ることができる場合に設定されるだろう、私はそうStreamIterableその要素の。


@ナマン関連ですが、これはバジルがこのQ&Aで行っていることの逆のようです。
スロー

1
Iterableを取得する別の方法は、リストに収集することです。
マット

回答:


12

で説明したように、なぜストリーム<T>は反復処理可能<T>を実装していませんか?IterableクマはIterator2回以上提供できるという期待を抱きますが、それStreamは満たすことができません。したがって、アドホックな用途のためにを作成するIterableことはできますが、Streamそれを複数回反復する試みが存在する可能性があるかどうかに注意する必要があります。

文字列のこれらの部分をIterable特定のライブラリに渡す必要がある」とおっしゃったので使用するコードIterableはコントロールの範囲外なので、一般的な解決策はありません。

しかし、あなたがストリームを作成する人である場合IterableIteratorリクエストされるたびに単にストリームの構築を繰り返すバリッドを作成することが可能です:

Iterable<String> lines = () -> "this\nthat\nthe_other".lines().iterator();

これは、任意の数の反復をサポートするという期待を満たしますが、1回だけトラバースされる場合、単一のストリームよりも多くのリソースを消費しません。

for(var s: lines) System.out.println(s);
lines.forEach(System.out::println);
System.out.println(String.join("\n", lines));

素晴らしい説明。(少し高度な補遺として)追加する価値があるかもしれませんが、Iterable<String> lines = "this\nthat\nthe_other".lines()::iterator;これはメソッド参照がラムダと同じではなく、実際に望ましくない影響を与えるまれなケースの1つであると言えます。
クリトスキリアクー

3
フォームの@KlitosKyriacouメソッド参照は、expression::nameラムダ式と同じになることはありませんSystem.out::println。しかし、ここでは、問題が発生するケースの1つである
Holger

この場合、ラインは毎回呼び出されStream<String> lines = str.lines();ますが、Iterable<String> iter = lines::iteratorとを作成した場合、メソッドとラムダの違いはわかりません()->lines.iterator()
マット

2
@mattはとの間に違いがあるstream::iteratorとは誰も言っていません() -> stream.iterator()。実際、私の答えは正確に言っています。既存のストリームを、複数の反復を可能にする有効な反復可能オブジェクトに変換する一般的な解決策はありません。イテレータが要求されるたびにストリームの構築を繰り返すこと、つまり、ここではlines()毎回呼び出すことを意味します。
Holger

3
@mattよく、正式には、同じではありません。expression::name手段は、「評価しexpressionたら、結果をキャプチャするのに対し、」() -> expression.name(…)手段「は、評価expression関数本体が評価されるたびに」。“ expression”がローカル変数だけの場合、違いはわずかですが、それでも異なります。つまりstream::iterator、の() -> stream.iterator()場合streamとは動作が異なりnullます。したがって、私の声明はまだ保持されており、expression::name常にラムダ式とは異なります。問題は、特定のユースケースでどれほど重要かということです。
Holger

3

tl; dr

キャストするだけで、変換する必要はありません。

にキャストStream < String >Iterable < String >ます。

細部

注意ストリームバックを使用することの危険性を説明するHolgerの回答を参照してくださいIterable

はい、あなたはIterableから作ることができますStream

解決策は簡単ですが、明白ではありません。Maurice NaftalinのLambda FAQのこの投稿を参照しください

iterator()上の方法BaseStream(のスーパークラスStream)を返すIteratorの同じ名前と一致するように起こるiterator()戻す方法Iteratorによって必要とされるIterableインターフェース。メソッドシグネチャが一致します。私たちが実際にキャストすることができるようStreamIterable、変換は必要ありません。

入力を行います。

String input = "this\n" +
        "that\n" +
        "the_other";
Stream < String > stream = input.lines() ;

それStream<String>をにキャストしてくださいIterable<String>

Iterable< String > iterable = ( Iterable < String > ) stream ;  // Cast `Stream < String >` to `Iterable < String >`. 

結果をテストします。

for ( String s : iterable ) 
{
    System.out.println( "s = " + s );
}

IdeOne.comでこのコードがライブで実行されるのをご覧ください

s =これ

s =それ

s = the_other

警告ストリームバックのリスクに注意してくださいIterableHolgerによる正しい回答で説明されています。


7
技術的には、はタイプではないStream<String>ため、キャスト元でstream::iteratorはありませんStream<String>
kaya3

3
キャストが正しい用語かどうかはわかりません。あなたはしているの作成のインスタンスIterableメソッド参照スルーを。(Iterable<String>)ただ機能インタフェースが対象で、コンパイラに指示します。
スローヤン23、1:

@Slaw&@ kaya3これらの微妙さは私の理解を逃れてしまいました。(Iterable<String>)キャスト以外の方法はわかりませんが、確かに状況を理解していません。コメント( (Iterable<String>) stream )が原因で、括弧を追加してコードが失敗する原因となるため、理解に欠陥があることがわかります。そのため、明確にするために私の回答を編集するか、より適切な説明を含む独自の回答を投稿してください。
バジルブルク

4
@Slaw問題は、キャストがあることは正しいですが、キャストが解決策であると言うのは正しくありません。ソリューションは、メソッド参照とキャストで構成されています。キャストは、意図したターゲットタイプを提供する別の構成要素で置き換えることができます。たとえば、メソッド参照を反復可能であることが期待されるメソッドに渡すか、反復可能タイプの変数に割り当てます。ただし、このソリューションでは、変換のためにメソッド参照またはラムダ式が必要です。したがって、変換(アダプターコード)キャストがまだある場合に変換ではなくキャストする」と言うのはナンセンスです。
Holger

2
Iterableは事実上機能的なインターフェースであり、stream.iteratorによってオーバーライドされたiteratorメソッドでIterableを作成しています。それは事実上、(Iterable<String>)()->stream.iterator()またはさらに明示的になりnew Iterable<String>(){ public Iterator<String> iterator(){ return stream.iterator();}ます。したがって、ストリームをIterableにキャストしていないため、失敗します。
マット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.