Подтвердить что ты не робот

Конечный поток Stream в Java - как его создать?

В Java можно легко создать бесконечный поток с Stream.generate(supplier). Тем не менее, мне нужно будет создать поток, который в конечном итоге закончится.

Представьте, например, что я хочу поток всех файлов в каталоге. Количество файлов может быть огромным, поэтому я не могу собрать все данные заранее и создать поток из них (через collection.stream()). Мне нужно сгенерировать последовательность по частям. Но в какой-то момент поток, очевидно, завершится, и терминальные операторы, такие как (collect() или findAny()), должны работать над ним, поэтому Stream.generate(supplier) здесь не подходит.

Есть ли разумный простой способ сделать это в Java, не реализуя весь интерфейс Stream самостоятельно?

Я могу думать о простом взломе - делать это с бесконечным Stream.generate(supplier) и предоставлять null или бросать исключение, когда принимаются все фактические значения. Но это нарушит стандартные потоковые операторы, я могу использовать его только с моими собственными операторами, которые знают об этом поведении.

РАЗЪЯСНЕНИЕ

Люди в комментариях предлагают мне оператор takeWhile(). Это не то, что я имел в виду. Как лучше сформулировать вопрос... Я не спрашиваю, как фильтровать (или ограничивать) существующий поток, я спрашиваю, как создавать (генерировать) поток - динамически, без загрузки всех элементов вверх, но поток будет иметь конечный размер (неизвестно заранее).

Решение

Код, который я искал,

    Iterator it = myCustomIteratorThatGeneratesTheSequence();
    StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false);

Я просто просмотрел java.nio.file.Files, как реализуется метод list(path).

4b9b3361

Ответ 1

Есть ли разумный простой способ сделать это в Java, не реализуя весь интерфейс Stream самостоятельно?

Простой .limit() гарантирует, что он завершится. Но это не всегда достаточно мощно.

После методов Stream factory простейший подход для создания источников таможенного потока без переопределения конвейера обработки потока заключается в подклассе java.util.Spliterators.AbstractSpliterator<T> и передаче его в java.util.stream.StreamSupport.stream(Supplier<? extends Spliterator<T>>, int, boolean)

Если вы собираетесь использовать параллельные потоки, обратите внимание, что AbstractSpliterator дает только субоптимальное расщепление. Если у вас больше контроля над исходным кодом, полное внедрение интерфейса Spliterator может быть лучше.

Например, следующий фрагмент создаст поток, обеспечивающий бесконечную последовательность 1,2,3...

в этом конкретном примере вы можете использовать IntStream.range()

Но поток, очевидно, завершится в какой-то момент, и операторы терминалов, такие как (collect() или findAny()), должны работать над ним.

операции короткого замыкания, такие как findAny(), могут заканчиваться бесконечным потоком, если есть какой-либо элемент, который соответствует.