Когда я выполняю этот код, который открывает много файлов во время конвейера потока:
public static void main(String[] args) throws IOException {
Files.find(Paths.get("JAVA_DOCS_DIR/docs/api/"),
100, (path, attr) -> path.toString().endsWith(".html"))
.map(file -> runtimizeException(() -> Files.lines(file, StandardCharsets.ISO_8859_1)))
.map(Stream::count)
.forEachOrdered(System.out::println);
}
Я получаю исключение:
java.nio.file.FileSystemException: /long/file/name: Too many open files
Проблема заключается в том, что Stream.count
не закрывает поток, когда он проходит его. Но я не понимаю, почему это не должно, учитывая, что это терминальная операция. То же самое относится к другим терминальным операциям, таким как reduce
и forEach
. flatMap
, с другой стороны, закрывает потоки, из которых он состоит.
Документация говорит мне использовать инструкцию try-with-resouces для закрытия потоков, если это необходимо. В моем случае я мог бы заменить строку count
на что-то вроде этого:
.map(s -> { long c = s.count(); s.close(); return c; } )
Но это шумно и уродливо и может быть настоящим неудобством в некоторых случаях с большими сложными конвейерами.
Итак, мои вопросы таковы:
- Почему потоки не были разработаны так, чтобы терминальные операции закрывали потоки, над которыми они работают? Это улучшит их работу с потоками ввода-вывода.
- Какое оптимальное решение для закрытия потоков ввода-вывода в конвейерах?
runtimizeException
- это метод, который обертывает проверенное исключение в RuntimeException
s.