Java 8には、クラス Stream <T> があり、不思議なことにメソッドがあります
Iterator<T> iterator()
したがって、インターフェイス Iterable <T> を実装することを期待します。これは、まさにこのメソッドを必要としますが、そうではありません。
Foreachループを使用してStreamを反復処理する場合、次のようなことをする必要があります
public static Iterable<T> getIterable(Stream<T> s) {
return new Iterable<T> {
@Override
public Iterator<T> iterator() {
return s.iterator();
}
};
}
for (T element : getIterable(s)) { ... }
ここに何かが足りませんか?
すでに同じ質問が寄せられています メーリングリスト上 ☺。主な理由は、Iterableには反復可能なセマンティックがありますが、Streamにはないということです。
主な理由は、
Iterable
が再利用性を意味するのに対し、Stream
は一度しか使用できないもので、より多くの場合はIterator
のようだと思います。
Stream
がIterable
を拡張した場合、既存のコードがfor (element : iterable)
を2回目にIterable
をスローするException
を受け取ったときに驚くかもしれません。
Stream
をIterable
に変換するには、次のようにします。
Stream<X> stream = null;
Iterable<X> iterable = stream::iterator
Stream
を期待するメソッドにIterable
を渡すには、
void foo(Iterable<X> iterable)
単に
foo(stream::iterator)
ただし、おそらく面白そうです。もう少し明示的にする方が良いかもしれません
foo( (Iterable<X>)stream::iterator );
StreamEx
はIterable
(およびStream
)と、Stream
にない他の非常に素晴らしい機能のホストを実装していることを指摘したいと思います。
kennytmの説明Stream
をIterable
として扱うのが安全でない理由、および Zhong Yuが回避策を提供Stream
の使用を許可する安全ではありませんが、Iterable
のように。 Iterable
仕様によって行われたすべての保証を満たすStream
から再利用可能なIterable
の両方の長所を得ることができます。
注:SomeType
はここでは型パラメーターではありません。適切な型(たとえば、String
)に置き換えるか、リフレクションに頼る必要があります
Stream<SomeType> stream = ...;
Iterable<SomeType> iterable = stream.collect(toList()):
1つの大きな欠点があります。
遅延反復の利点は失われます。現在のスレッドのすべての値をすぐに反復する場合、オーバーヘッドは無視できます。ただし、部分的にのみ、または別のスレッドで反復することを計画している場合、この即時の完全な反復により、意図しない結果が生じる可能性があります。
もちろん、大きな利点はIterable
を再利用できることですが、(Iterable<SomeType>) stream::iterator
は1回しか使用できません。受信するコードがコレクションを複数回繰り返し処理する場合、これは必要なだけでなく、パフォーマンスにとっても有益です。
次のように、for
ループでStreamを使用できます。
Stream<T> stream = ...;
for (T x : (Iterable<T>) stream::iterator) {
...
}
(実行 このスニペットはこちら )
(これはJava 8機能インターフェースキャストを使用します。)
(これは上記のコメントの一部でカバーされています(例: Aleksandr Dubinsky )が、よりわかりやすくするために回答に引き出したいと思いました。)
Stream
はIterable
を実装しません。 Iterable
の一般的な理解は、何度も何度も繰り返すことができるものです。 Stream
は再生できない場合があります。
私が考えることができる唯一の回避策は、ストリームに基づいた反復可能なものも再生可能である場合、ストリームを再作成することです。新しいイテレータが作成されるたびに、以下のSupplier
を使用してストリームの新しいインスタンスを作成しています。
Supplier<Stream<Integer>> streamSupplier = () -> Stream.of(10);
Iterable<Integer> iterable = () -> streamSupplier.get().iterator();
for(int i : iterable) {
System.out.println(i);
}
// Can iterate again
for(int i : iterable) {
System.out.println(i);
}
サードパーティのライブラリを使用してもかまわない場合 cyclops-react は、StreamとIterableの両方を実装し、再生可能なストリームを定義します(問題の解決 kennytm記述 )。
Stream<String> stream = ReactiveSeq.of("hello","world")
.map(s->"prefix-"+s);
または :-
Iterable<String> stream = ReactiveSeq.of("hello","world")
.map(s->"prefix-"+s);
stream.forEach(System.out::println);
stream.forEach(System.out::println);
[開示私はcyclops-reactのリード開発者です]
次のようにStream<Path>
を使用して、フォルダー内のすべてのファイルを反復処理できます。
Path path = Paths.get("...");
Stream<Path> files = Files.list(path);
for (Iterator<Path> it = files.iterator(); it.hasNext(); )
{
Object file = it.next();
// ...
}