Search code examples
javajava-8java-stream

Do terminal operations on streams close the source?


Consider the following code:

Path directory = Paths.get(/* some directory */);
Files.list(directory).forEach(System.out::println);

Does a terminal operation (like forEach) close the underlying file that has been opened?

Refer to the relevant parts of the javadoc of Files.list:

The returned stream encapsulates a DirectoryStream. If timely disposal of file system resources is required, the try-with-resources construct should be used to ensure that the stream's close method is invoked after the stream operations are completed.

If it doesn't call Stream.close(), what would then be the best alternative to call it while producing maintainable code?


Solution

  • Terminal operators do NOT close the stream automatically. Consider this code:

    Stream<Path> list = Files.list(directory).onClose(() -> System.out.println("Closed"));
    list.forEach(System.out::println);
    

    This does NOT print "Closed".

    However, the following does print "Closed":

    try (Stream<Path> list = Files.list(directory).onClose(() -> System.out.println("Closed"))) {
        list.forEach(System.out::println);
    }
    

    So the best way to do it is to use the try-with-resources mechanism.

    In Java 9+, the resource can be declared and instantiated before the try. See JEP 213.

    Stream<Path> list = Files.list(directory).onClose(() -> System.out.println("Closed")) ;
    …
    try (list) {
        list.forEach(System.out::println);
    }