Должны ли экземпляры Java 8 Stream всегда быть close () 'd?

12

Квот Javadoc :

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

«Почти все» и «в целом» являются расплывчатыми - если вы пишете библиотеку и абстрагируете источник вашего потока от пользователей этого потока, то вам все равно придется задать себе вопрос - «должен ли я закрыть это?" Потоки, поддерживаемые IO, должны быть закрыты, потому что терминальные операции не вызывают close, поэтому мне всегда нужно либо помнить / документировать, откуда поступает мой поток, либо я всегда должен closeэто делать .

Ядерная опция, я думаю, состояла бы в том, чтобы не возвращать Streams из методов или принимать параметры Stream, что является мнением, которое повторяют некоторые люди из команды JDK. Я считаю это чрезмерным ограничением, учитывая практическую полезность потоков.

Каковы ваши лучшие практики закрытия потоков? Я искал в Интернете ответ на этот вопрос от некоторых людей из JDK, которые обычно работают над похожими вопросами сообщества, но не находят ничего актуального.

Русланд
источник
Не Java-разработчик, но я бы использовал следующие правила: - Если поток передается в качестве аргумента, документально подтвердите, что вызывающая сторона должна закрыть поток при необходимости; - Если поток возвращается вам из функции, предположим, что вам нужно закрыть его.
Барт ван Инген Шенау

Ответы:

6

Как вы сказали, в Java вам нужно точно знать, кто отвечает за освобождение того или иного ресурса, чтобы вы могли вставить соответствующие конструкции try-catch-, try-with-resources или как-то делегировать эту задачу.

Единственное, что вы можете рассчитывать на очистку GC - это 100% чистая память.
Если могут быть смешаны какие-то другие ресурсы, единственное, что вы можете разумно сделать, это просто не рисковать.

Deduplicator
источник
Так в принципе closeэто единственная безопасная альтернатива? Я предполагаю, что вопрос состоит в том, чтобы не делать код слишком уродливым каждый раз, когда было бы удобно использовать Stream.
РусланД
1
Да, если могут быть ресурсы, не связанные с памятью, единственное, что нужно сделать, это предположить, что они есть . Обойти это невозможно, хотя Java очень плохо подходит для ресурсов, не относящихся к GC.
дедупликатор
Так что, если это просто поток между двумя коллекциями (чистая память), закрывать его не нужно?
Амальговинус
@Amalgovinus правильно
Брэд Купит
5

Что касается «лучших практик», я думаю, что было бы неплохо использовать соглашение об именах для методов, которые возвращают «потоки ресурсов».

Если необходимо редактировать поток close(), вызовите метод фабрики open()или openStream(). Вызовите методы, которые stream()создают эфемерные потоки в соответствии с соглашением, установленным SDK. Всегда ставьте javadoc на метод, чтобы предупредить клиента, что он должен close()это сделать.

public interface StreamingServer<RECORD> {
    /** 
     * Return a memory-efficient record stream from {@code source}.
     * Clients <em>must</em> call {@link Stream#close} to dispose the
     * stream.
     */
    Stream<RECORD> openStream(URI source) throws IOException;
}

Я бы хотел, чтобы авторы SDK не выбрали вариант AutoCloseableбазового потока. Отдельный ResourceStreamподтип, который тривиально реализует AutoCloseable, сделал бы разные контракты очевидными. Тогда вы не сможете закрыть объект, Streamкоторый ему не нужен, и вы можете обнаружить потенциально неправильно ResourceStreamуправляемые инструменты статического анализа.

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

@RequiresClose
Stream<RECORD> openStream(URI source) throws IOException { ... }
Джейсон Трамп
источник