Short answer
Files.walk returns a lazy Stream<Path> and is concise, but it holds open directory handles (use try-with-resources), can throw partway through on an unreadable entry, and by default does not follow symlinks (FOLLOW_LINKS risks infinite cycles).
Explanation
Files.walkFileTree with a FileVisitor is more verbose but gives fine-grained control: you can handle visit failures per-file, prune subtrees with SKIP_SUBTREE, and post-visit directories — which is exactly what you need to implement a correct recursive delete (delete children before the directory).
Common mistakes
- Not closing the Stream from Files.walk.
- Following symbolic links into cycles.