When the first version of this post was published, a search on the web for “recursive file java” returned only horrible examples on how to implement directory traversal. I published a version based on anonymous classes to improve on that. More than 10 years later it’s time to re-evaluate.
File.walk java has gotten a streaming API that visits the given path in a depth-first manner. The most commonly found example is simple and straight forward.
Unfortunately, a “hello world” example like this hides the shortcomings in real-world usage scenarios. While you can filter the emitted paths of the stream, there is no way to skip directories during traversal. Even worse - there is no way to gracefully handle exceptions that are bound to happen. With
Files.find you can pass in a predicate that might help to reduce redundant retrieval of file attributes - but other than that it suffers from the very same problems. I’d recommend avoiding both API methods because of that.
Using the Visitor
This leaves us with
Files.walkFileTree which accepts a
FileVisitor instead of returning a stream.
I’ve never been a fan of the formal implementation of the Visitor pattern and I would use a base class
FileTraversal to get rid of some of the cruft of the interface. But even with that the minimal code becomes quite long.
If you just extend the
SimpleFileVisitor it comes quite close to the original version using the old File interface. Except that I find the old code still much easier to read and understand. I do believe this code has aged gracefully.
While the anonymous class approach never felt great it was quite effective. Despite being a believer in delegation over inheritance, even now with lambdas, I could not come up with a concise version that mirrors the elegance. This mostly stems from the way lambdas are implemented in java though.
With a fluent API, it would be less verbose but bloat the visitor implementation. I am not sure how much better this is when you transition to multi-line lambdas though.
What would should you use today? To be completely honest - work on a vistor class that works for your use case. Base it off the
SimpleFileVisitor. At least in theory the visitor would also allow for some paralelisation. If you hide away the code you could even use lambdas. But if you don’t have a reason - no need to replace the old code.