Search code examples
javajava-stream

Using try with resources for a Java Files.walk stream created in a separate method


Working on a project I encountered a situation which I do not know how to properly solve. I am not sure if my solution is the best I could use. But let me introduce the problem (I reproduced it as simply as I could).

There is a class (which is not properly written) which simply gets filenames from directory:

public class StreamTest
{
    public List<String> getList(Path dir) {
        return getStream(dir)
                .map(filename -> filename.toString())
                .collect(Collectors.toList());

    }


    private Stream<Path> getStream(Path dir)
    {
        if (Files.exists(dir)) {

            try {
                Stream<Path> stream = Files.walk(dir, 1);

                return stream
                        .filter(Files::isRegularFile)
                        .map(dir::relativize);
            } catch (IOException e) {
                System.out.println("Error");
            }
        }

        return null;
    }
}

and Main.class

public class Main {
    public static void main(String[] args) {

        Path dir = Paths.get("C:\\Projects\\Tests\\Walk");

        StreamTest streamTest = new StreamTest();

        List<String> list = streamTest.getList(dir);

        System.out.println(list);
    }
}

It works but you see what's wrong? Files.walk(dir, 1) should be run with try-with-resources.

But when I replace:

try {
    Stream<Path> stream = Files.walk(dir, 1);

with

try (Stream<Path> stream = Files.walk(dir, 1)) {

I receive IllegalStateException.

And now question:

Is this approach correct at all? I mean getting stream from method and working on it? But how to properly use try-with-resources in that situation?

The workaround is to return List of some mapped type (e.g String) instead of Stream from getStream and work with it in getList method but I am curious if there is good answer to the question asked.

Certainly I may do all job in one method but hypothetically I may call getStream from couple of other methods.


Solution

  • I receive IllegalStateException.

    That's because you've closed the stream before you try to access anything from it. A try-with-resources in the getStream method will close the stream when that method returns; so you won't be able to read the stream in getList.

    Put the try-with-resources in getList:

        public List<String> getList(Path dir) {
            try (Stream<Path> stream = getStream(dir)) {
              return stream
                      .map(filename -> filename.toString())
                      .collect(Collectors.toList());
            }
    
        }