检索文件夹和子文件夹以使用尾递归在java中读取文件

问题描述 投票:1回答:1

我正在使用正常的递归方法来迭代并从java中的文件夹和子文件夹中获取文件。

有人可以帮助我改变尾部递归方法吗?我无法理解尾递归是什么。这对我来说很有用。

public void findFiles(String filePath) throws IOException {
    List<File> files = Files.list(Paths.get(filePath))
                            .map(path -> path.toFile())
                            .collect(Collectors.toList());

    for(File file: files) {
        if(file.isDirectory()){ 
                if(file.list().length == 0){
                        boolean isDeleted = file.delete();

                }else{
                    findFiles(file.getAbsolutePath());
                }
        }else{
            //process files
        }
    }
}

这是我的正常递归,有人可以帮我写这个尾递归吗?

我尝试了一种方法,但我不确定这是否是尾递归及其工作原理。

public static void findFiles(String filePath) throws IOException{
    List<File> files = Files.list(Paths.get(filePath))
                            .map(path -> path.toFile())
                            .collect(Collectors.toList());

    for(File file: files) {
        if(file.isDirectory() && file.list().length == 0){
             boolean isDeleted = file.delete();
        }else if(!file.isDirectory()){
                System.out.println("Processing files!!!" +  file.getAbsolutePath());
        }
        if(file.isDirectory()) {
                findFiles(file.getAbsolutePath());
        }
    }

}

提前致谢。

java recursion java-8 filesystems tail-recursion
1个回答
3
投票

尾递归是一种特殊的递归,它在递归调用之后不做任何事情但返回。

一些编程语言通过优化调用堆栈来利用这一点,因此如果你有一个非常深的递归,你不会最终出现堆栈溢出(除了内存和调用效率增益本身)。

经常使用的技巧是添加一个额外的累加器参数,该参数可以处理任何未完成的数据。由于这可能使递归函数不太可用,因此它通常是单独完成的,因此对于函数的用户来说它看起来很简单。

所以在你的例子中它就像这样,正常的findFiles()只是准备递归调用,而private findFilesRecursive()正在进行尾递归工作。

public void findFiles(String filePath) throws IOException {
  //we use a Deque<> for Last In First Out ordering (to keep subfolders with their parent)
  Deque<Path> paths = new ArrayDeque<Path>();  
  paths.add(Paths.get(filePath);
  return findFilesRecursive(paths);  
}

private void findFilesRecursive(Deque<Path> pending) {
  if (pending.isEmpty()) {
    //base case, we are ready
    return;
  }

  Path path = pending.removeFirst();
  if (Files.isRegularFile(path)) {
    //todo: process the file

  } else {
      //it is a directory, queue its subfolders for processing
     List<Path> inside = Files.list(path).collect(Collectors.toList());
     if (inside.isEmpty() {
       Files.delete(path);
     } else {
       //we use LIFO so that subfolders get processed first
       inside.forEach(pending::addFirst);
     }
  }

  //tail recursion, we do nothing after we call it
  return findFilesRecursive(pending);  
}

请注意,Java不会(yet)利用尾递归。其他编程语言,如Scala和Kotlin。

旁注,Path通常比旧的File更强大,你不需要在你的情况下将Path改为File

© www.soinside.com 2019 - 2024. All rights reserved.