Вы все еще используете Files.lines()?

Привет, и в очередной раз мы поговорим про новшества Java 8, а точнее Files.lines().

Что может быть проще:

[code lang=”java”]public class FilesLines {

public static void main(String[] args) throws Exception {

Path path = Paths.get(“/home/ruslan/test.txt”);

for (int i = 0; i < 10000; i++) {
Files.lines(path).count();
}
}
}[/code]

Создаем стринговый стрим из файла делаем какие-то операции со стримом и продолжаем работу, стрим же сам о всем позаботиться.

Запустим этот код под Ubuntu 14.04

[code lang=”bash”]java -version
java version “1.8.0_31″
Java(TM) SE Runtime Environment (build 1.8.0_31-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)[/code]

Результат:

[code lang=”java”]Exception in thread “main” java.nio.file.FileSystemException: /home/ruslan/test.txt: Too many open files
at sun.nio.fs.UnixException.translateToIOException(UnixException.java:91)
at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)
at sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:214)
at java.nio.file.Files.newByteChannel(Files.java:361)
at java.nio.file.Files.newByteChannel(Files.java:407)
at java.nio.file.spi.FileSystemProvider.newInputStream(FileSystemProvider.java:384)
at java.nio.file.Files.newInputStream(Files.java:152)
at java.nio.file.Files.newBufferedReader(Files.java:2784)
at java.nio.file.Files.lines(Files.java:3744)
at java.nio.file.Files.lines(Files.java:3785)
at by.ibragimov.jpress.FilesLines.main(FilesLines.java:14)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)[/code]

wtf

Что-же говорит нам документация? Посмотрим: File#lines(Path path) не содержит ничего подозрительного, но внутри просто делегирует вызов в Files#lines(Path path, Charset cs), а вот тут уже JavaDoc’и на намекают:

[code lang=”java”] /**
* …
* The returned stream encapsulates a {@link Reader}. If timely
* disposal of file system resources is required, the try-with-resources
* construct should be used to ensure that the stream’s
* {@link Stream#close close} method is invoked after the stream operations
* are completed.
* …
*/[code]

Ну и исправленная версия напоследок:

[code lang=”java”]public class FilesLines {

public static void main(String[] args) throws Exception {

Path path = Paths.get("/home/ruslan/test.txt");

for (int i = 0; i < 10000; i++) {
try(Stream<String> stream = Files.lines(path)) {
stream.count();
}
}
}
}[/code]

Вывод как всегда один: читайте документацию.

Leave a Reply

Your email address will not be published. Required fields are marked *