Как создать поток Java 8 из итератора?

Возможно ли создать поток из Итератора, в котором последовательность объектов будет такой же, как и сгенерированная повторением метода iterator next()? В конкретном случае, о котором я думаю, речь идет об использовании итератора, возвращаемого TreeSet.descendingIterator(), но я могу представить другие обстоятельства, в которых доступен итератор, но не его коллекция.

Например, для TreeSet<T> tset мы можем написать tset.stream()... и получить поток объектов в этом наборе в заданном порядке сортировки, но что, если мы хотим, чтобы они были в другом порядке, например, через используя descendingIterator()? Я представляю что-то вроде tset.descendingIterator().stream()... или stream( tset.descendingIterator() )..., хотя ни одна из этих форм не действительна.

Ответ 1

Для конкретного примера NavigableSet.descendingIterator() я думаю, что самый простой способ - использовать NavigableSet.descendingSet().

Но, учитывая, что вы, вероятно, заинтересованы в более общем случае, кажется, что работает следующее:

import java.util.Iterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.TreeSet;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

public class Streams {
    public static void main(String... args) {
        TreeSet<String> set = new TreeSet<>();
        set.add("C");
        set.add("A");
        set.add("B");

        Iterator<String> iterator = set.descendingIterator();

        int characteristics = Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED;
        Spliterator<String> spliterator = Spliterators.spliteratorUnknownSize(iterator, characteristics);

        boolean parallel = false;
        Stream<String> stream = StreamSupport.stream(spliterator, parallel);

        stream.forEach(System.out::println); // prints C, then B, then A
    }
}

Короче, вам нужно сначала создать Spliterator из Iterator, используя один из статических методов в Spliterators. Затем вы можете создать Stream, используя статические методы в StreamSupport.

У меня не так много опыта с созданием Spliterators и Streams вручную, поэтому я не могу прокомментировать, какими должны быть характеристики или какой эффект они будут иметь. В этом конкретном простом примере, казалось, не имеет значения, определил ли я характеристики, как указано выше, или установил ли я его 0 (т.е. Никаких характеристик). Существует также метод в Spliterators для создания Spliterator с начальной оценкой размера. Предположим, что в этом конкретном примере вы можете использовать set.size(), но если вы хотите обрабатывать произвольные итераторы, я думаю, это не так. Опять же, я не совсем уверен, какой эффект он оказывает на производительность.

Ответ 2

static <T> Stream<T> iteratorToFiniteStream(final Iterator<T> iterator) {
    return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
}

static <T> Stream<T> iteratorToInfiniteStream(final Iterator<T> iterator) {
    return Stream.generate(iterator::next);
}

Ответ 3

Это не создает поток, но Iterator также имеет метод forEachRemaining:

someIterator.forEachRemaining(System.out::println);
someIterator.forEachRemaining(s -> s.doSomething());
//etc.

Аргумент, который вы передаете, - это Consumer, который является тем же самым, что вы переходите на Stream:: forEach.

Ниже приведены документы для этого метода. обратите внимание, что вы не можете продолжать "цепочку" , как вы можете, с потоком. Но я все же нашел это полезным несколько раз, когда мне нужен Stream из Iterator.