web-dev-qa-db-ja.com

イテレータをストリームに変換する方法

私は IteratorStream に変換する簡潔な方法、またはより具体的にはイテレータをストリームとして "見る"方法を探しています。

パフォーマンス上の理由から、新しいリストではイテレータのコピーを避けたいと思います。

Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Collection<String> copyList = new ArrayList<String>();
sourceIterator.forEachRemaining(copyList::add);
Stream<String> targetStream = copyList.stream();

コメント内のいくつかの提案に基づいて、私は Stream.generate を使用することも試みました。

public static void main(String[] args) throws Exception {
    Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
    Stream<String> targetStream = Stream.generate(sourceIterator::next);
    targetStream.forEach(System.out::println);
}

しかし、私はNoSuchElementExceptionを受け取ります(hasNextの呼び出しはないので)

Exception in thread "main" Java.util.NoSuchElementException
    at Java.util.AbstractList$Itr.next(AbstractList.Java:364)
    at Main$$Lambda$1/1175962212.get(Unknown Source)
    at Java.util.stream.StreamSpliterators$InfiniteSupplyingSpliterator$OfRef.tryAdvance(StreamSpliterators.Java:1351)
    at Java.util.Spliterator.forEachRemaining(Spliterator.Java:326)
    at Java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.Java:580)
    at Main.main(Main.Java:20)

StreamSupportCollections を見ましたが、何も見つかりませんでした。

381
gontard

1つの方法は、IteratorからSpliteratorを作成し、それをストリームの基盤として使用することです。

Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Stream<String> targetStream = StreamSupport.stream(
          Spliterators.spliteratorUnknownSize(sourceIterator, Spliterator.ORDERED),
          false);

もっと読みやすい代替方法はIterableを使用することです - Iterableは機能的なインタフェースなので、IteratorからIterableを作成するのはとても簡単です。

Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();

Iterable<String> iterable = () -> sourceIterator;
Stream<String> targetStream = StreamSupport.stream(iterable.spliterator(), false);
445
assylias

バージョン21以降、Guavaライブラリは Streams.stream(iterator) を提供しています。

@ assylias answerが示すことを行います。

88
numéro6

大提案!これが私の再利用可能な話です。

public class StreamUtils {

    public static <T> Stream<T> asStream(Iterator<T> sourceIterator) {
        return asStream(sourceIterator, false);
    }

    public static <T> Stream<T> asStream(Iterator<T> sourceIterator, boolean parallel) {
        Iterable<T> iterable = () -> sourceIterator;
        return StreamSupport.stream(iterable.spliterator(), parallel);
    }
}

そして使用法(静的にasStreamをインポートするようにしてください):

List<String> aPrefixedStrings = asStream(sourceIterator)
                .filter(t -> t.startsWith("A"))
                .collect(toList());
81
Matan

これはJava 9ではストリーム以外は何も使用しないで可能ですが、注意が必要です。次の単純な例では、 イテレータの最後の要素 を表示できません。

Stream.generate(iterator::next)
    .takeWhile(i -> iterator.hasNext()) 
    .forEach(System.out::println);

ただし、これは正しく機能します。

Stream.generate(() -> null)
    .takeWhile(x -> iterator.hasNext())
    .map(n -> iterator.next())
    .forEach(System.out::println);
10
PhilipRoman

Spliteratorname__クラスを使用してIteratorname__からSpliteratorsname__を作成します。例えば、ここではイテレーターをパラメーターとして取得しているspliteratorUnknownSizename__を使用しています。そしてStreamSupportname__を使用してStreamを作成します。

Spliterator<Model> spliterator = Spliterators.spliteratorUnknownSize(
        iterator, Spliterator.NONNULL);
Stream<Model> stream = StreamSupport.stream(spliterator, false);
4