Java 8 Stream (на основе ресурса) .iterator(), который автоматически закрывает ресурс?

Есть ли Java 8 Stream.iterator() автоматически закрыть поток, когда это будет сделано? Я полагаю, нет...

У меня есть что-то вроде этого:

class Provider implements Serializable {

  Iterator<String> iterator() {
    Stream<String> stream = new BufferedReader(...).lines();
    return stream.iterator();
  }
}

Этот итератор используется другим классом, который не знает, что итератор основан на ресурсе чтения файлов. То есть

class Consumer {
  void f() {
    Iterator<String> iterator = provider.iterator();
    // code that calls iterator methods at non-determined times
  }
}

Я должен передать файл, потому что он слишком большой, чтобы поместиться в память. Но я хотел бы иметь возможность автоматически закрывать ресурс, когда у итератора больше нет элементов, чтобы у меня не было утечек ресурсов. Provider класс Serializable и я не могу иметь ни Stream, ни BufferedReader в качестве участников.

Есть ли хороший способ сделать это?

1 ответ

Во-первых, обратите внимание, что ваш поток создан из BufferedReader.lines не содержит никаких ресурсов, поэтому закрытие потока не имеет никакого эффекта:

BufferedReader br = new BufferedReader(...);
try(Stream<String> stream = br.lines()) {
   ... use stream
}
// br is still open here!

Обычно это явно задокументировано, если поток содержит ресурс. Например, Files.lines документы это:

Возвращенный поток инкапсулирует Reader, Если требуется своевременное удаление ресурсов файловой системы, следует использовать конструкцию try-with-resources, чтобы гарантировать, что поток close Метод вызывается после завершения потоковых операций.

Там нет такого замечания в BufferedReader.lines документация.

Так что в вашем случае это ваша ответственность, чтобы закрыть BufferedReader если он действительно содержит ресурс, который должен быть закрыт. Это не всегда так. Например, если вы создаете new BufferedReader(new StringReader(string)), у вас нет ресурсов для закрытия, так что просто не вызывать close() метод вообще.

В любом случае, вернемся к вашему вопросу. Предполагая, что поток действительно содержит ресурс (например, создан из Files.lines()), он не будет закрыт автоматически, если вы просто вернете итератор, независимо от того, пройден ли итератор до конца или нет. Вы должны явно назвать close() метод в потоке, если вы хотите закрыть его в определенный момент. В противном случае вам придется полагаться на сборщик мусора, который в конечном итоге поместит базовый ресурсный объект (например, FileInputStream) в очередь завершения, которая в конечном итоге вызовет finalize метод того объекта, который закроет файл. Вы не можете гарантировать, когда это произойдет.

Альтернативой может быть помещение в буфер всего входного файла (при условии, что он не очень длинный) и закрытие файла перед возвратом итератора. Вы можете сделать это для чтения файла без какого-либо потокового API:

return Files.readAllLines(pathToTheFile).iterator();
Другие вопросы по тегам