Мне нужно закрыть этот поток, созданный Files.lines:
Map<String, Long> wordCounts =
Files.lines(fileP, Charset.forName("UTF-8"))
.map(line -> line.replaceAll("[.?!]$"," % "))
.flatMap(line -> pattern.splitAsStream(line))
.collect(Collectors.groupingBy(String::toLowerCase,
TreeMap::new, Collectors.counting()));
Как мне быть?
Спасибо.
Согласно Javadoc
[..] Если требуется своевременная утилизация ресурсов файловой системы, следует использовать конструкцию try-with-resources, чтобы гарантировать вызов метода закрытия потока после завершения операций потока.
try (Stream<String> stream = Files.lines(fileP, Charset.forName("UTF-8"))) {
stream.map(line -> line.replaceAll("[.?!]$"," % "))
...//rest of code here
}
Files.lines
реализует AutoCloseable
, поэтому вы можете использовать try-catch
с ресурсами.
try(Stream<String> fileLines = Files.lines(fileP, Charset.forName("UTF-8"))){
Map<String, Long> wordCounts = fileLines.map(line -> line.replaceAll("[.?!]$"," % "))
.flatMap(line -> pattern.splitAsStream(line))
.collect(Collectors.groupingBy(String::toLowerCase,
TreeMap::new, Collectors.counting()));
}catch(Exception e){
e.printStackTrace();
}
После выполнения блока try
он автоматически вызывает fileLines.close()
P.S.: Прочитайте ответ rzwitserloot
, он содержит полезную информацию.
API потока не предназначен для использования таким образом. К сожалению, потоки / функциональные / необязательные и т. д. в настоящее время являются «изюминкой дня», и есть масса фанатиков и прозелитистов, которые нашли свою религию и теперь активно пытаются обратить каждую душу, которую они могут найти. Код, как вы его написали, выглядит для них «чистым» (термин в глазах смотрящего, но я вижу, как этот стиль кода выглядит хорошим для многих), и это распространяется на сами учебники по оракулу, которые ошибаться все время. Однако в javadoc четко указано, как вы должны использовать потоки. И это не так.
Из javadoc Files.lines
:
Возвращенный поток инкапсулирует Reader. Если требуется своевременная утилизация ресурсов файловой системы, следует использовать конструкцию try-with-resources, чтобы гарантировать вызов метода закрытия потока после завершения операций потока.
Это легкомысленное замечание; «если требуется своевременная утилизация ресурсов файловой системы» — это забавный способ сказать, «если вы хотите, чтобы ваша виртуальная машина не стала почти бесполезной из-за того, что у нее закончились дескрипторы файлов и существует риск сбоя из-за того, что вы даже не можете открыть jar для чтения в некоторых классах».
Таким образом, вы должны сделать то, что он говорит: обернуть их в блоки try-with-resources. Любой Stream
можно обернуть так (потому что Stream
реализует AutoClosable — у него есть метод close()
):
Map<String, Long> wordCounts;
try (var stream = Files.lines(fileP)) {
wordCounts = stream
.map(...)
.flatMap(...)
.collect(...);
}
NB: Указание UTF-8 здесь не требуется; в отличие от большинства базовых методов в среде выполнения ядра Java, все методы Files
, которые неявно преобразуют байты в символы или наоборот, будут использовать UTF-8, если вы не укажете кодировку.
NB2: Терминальные операции в потоке, такие как .collect
, заканчиваются закрытием основного потока, когда они выполнены. Проблема в том, что ваш поток останется незакрытым, если, например. одна из ваших .map
операций заканчивается броском.