Stream.spliterator() закрывает поток?

Ли stream.spliterator() неявно закрывает streamили есть необходимость явно закрыть его потом?

Stream<String> stream = Stream.of("a", "b", "c");
Spliterator<T> spliterator = stream.spliterator();
// Some low lever operation with the spliterator
stream.close(); // do we need to close?

На первый взгляд кажется, что .spliterator() метод закрывает stream, но без звонка stream.close(), По крайней мере, если я закрою его сразу после .spliterator() метод вызывается, кажется, не привязанность операций сплитератора.

Stream<String> stream = Stream.of("a", "b", "c").limit(2);
Spliterator<T> spliterator = stream.spliterator();
stream.close();
// Some low lever operation with the spliterator

Этот вопрос может быть распространен на других stream методы, например, .findAny(),

stream.findAny() // Can I assume that I don't need to close the stream?
stream.onClose(() -> System.out.println("hi!")).findAny()`
// when the `onClose()` action will be called?

Причина этого вопроса заключается в том, чтобы иметь stream необходимо явно закрыть, а в тех случаях, когда мне не нужно явно закрывать его, когда onClose() определенные действия будут иметь место?

3 ответа

Решение

Терминальные операции никогда не закрывают поток. Закрытие должно быть сделано вручную. Единственное место, где происходит автоматическое закрытие, находится в пределах flatMap операция, при которой ручное закрытие подпотоков, обычно создаваемых на лету, будет где-то между жестким и невозможным.

Это также относится к Stream.spliterator() метод. В ваших примерах это не имеет значения, потому что потоки, созданные с помощью Stream.of(…) не нужно закрываться и не иметь onClose операция зарегистрирована по умолчанию.

Вы должны обратиться к документации фабричных методов, чтобы узнать, когда поток должен быть закрыт, например, как с Files#lines(Path, Charset),

См. Также Закрывает ли операция сбора в потоке поток и базовые ресурсы? или делает Java 8 Stream.iterator() автоматически закрыть поток, когда это будет сделано?

Призыв к spliterator() метод возвращает Spliterator для элементов этого потока и его терминальной операции.

Чтобы ответить на ваш вопрос - нет, spliterator Метод или ради этого ни одна из других операций терминала также не закрывает поток.

Это документировано для терминальных операций как -

После того, как операция терминала выполнена, потоковый конвейер считается использованным и больше не может использоваться.... Почти во всех случаях терминальные операции стремятся завершить свой обход источника данных и обработать конвейер перед возвратом. Только терминальные операции iterator() а также spliterator() нет; они предоставляются в качестве "аварийного люка" для включения произвольных контролируемых клиентом обходов конвейера в случае, если существующие операции недостаточны для выполнения задачи.

За закрытие Stream с другой стороны, документы утверждают, что:

Большинство потоковых экземпляров на самом деле не нужно закрывать после использования, поскольку они поддерживаются коллекциями, массивами или генерирующими функциями, которые не требуют специального управления ресурсами. Как правило, только потоки, источником которых является канал ввода-вывода, такие как те, которые возвращены Files.lines(Path), потребует закрытия.


AutoCloseable состояния, чтобы соответствовать этому-

Для базового класса возможно и фактически является общим для реализации AutoCloseable, даже если не все его подклассы или экземпляры будут содержать высвобождаемые ресурсы.

как BaseStream расширяет его и close() не влияет больше, чем потоки на те, которые используют ресурсы, такие как Files.lines(...),

Однако при использовании таких средств, как Stream, которые поддерживают формы как на основе ввода / вывода, так и не на основе ввода / вывода, блоки пробного использования с ресурсами обычно не нужны при использовании форм не на основе ввода / вывода.

Ничего не изменилось в отношении закрытия Stream s в Java 9. Вам все еще нужно сделать это вручную, если основной ресурс должен быть освобожден. Вы никогда не должны полагаться на сборщик мусора, чтобы сделать это. Документы все еще говорят:

Потоки имеют BaseStream.close() метод и реализовать AutoCloseable, Работа с потоком после его закрытия вызовет IllegalStateException, Большинство потоковых экземпляров на самом деле не нужно закрывать после использования, поскольку они поддерживаются коллекциями, массивами или генерирующими функциями, которые не требуют специального управления ресурсами. Как правило, только потоки, источником которых является канал ввода-вывода, такие как те, которые возвращены Files.lines(Path) , потребует закрытия. Если поток требует закрытия, он должен быть открыт как ресурс внутри оператора try-with-resources или аналогичной структуры управления, чтобы обеспечить его немедленное закрытие после завершения его операций.

Метод stream.spliterator() не закрывает Stream, как никакой другой терминальной операции. Вы можете или не можете знать, если вам нужно закрыть StreamЭто все еще большая дискуссия. Я лично хотел бы иметь все терминальные операции, кроме spliterator() а также iterator() неявно закрыть Stream по разным причинам. В этом нет никакого вреда, так как большинство реализаций просто ничего не делают.

Вы можете найти одну реализацию в java.util.stream.AbstractPipeline, Действие закрытия, которое было добавлено при вызове stream.onClose(action) будет вызван в данный момент stream.close() называется.

Я не могу сказать вам, когда Stream явно должен быть закрыт, так как текущая политика должна документировать его в методе, который возвращает Stream, лайк Files.list(Path):

Возвращенный поток содержит ссылку на открытый каталог. Каталог закрывается при закрытии потока....

Этот метод должен использоваться в инструкции try-with-resources или аналогичной структуре управления, чтобы гарантировать, что открытый каталог потока будет закрыт сразу после завершения операций потока.

Когда вы звоните stream.spliterator()возвращенный Spliterator может быть ленивым (см. также AbstractPipeline.lazySpliterator(..)), при этом еще нужно оперировать элементами оригинала Stream, Если вы закроете Stream прежде чем пересечь элементы Spliterator, вы можете получить исключение или Spliterator просто больше не работает.

public static void main(final String[] args) throws IOException {
    try (final Stream<Path> stream = Files.list(Paths.get(""))) {
        stream.onClose(() -> System.out.println("stream closed"));
        final Spliterator<Path> split = stream.spliterator();

        /*
         * uncomment this to see what happens when you close the
         * stream before you traverse the spliterator
         */
        // stream.close();

        split.forEachRemaining(System.out::println);
    }
}

Проблема в том, что если вы хотите иметь метод, который возвращает SpliteratorУ звонящего нет close() метод, который можно вызвать на Spliterator,

Другие вопросы по тегам