Хвостовая рекурсия - это особый вид рекурсии, который ничего не делает после рекурсивного вызова , но возвращает.
Некоторые языки программирования используют это преимущество, оптимизируя стек вызовов, так что если у вас очень глубокая рекурсия, вы не получите переполнения стека (не считая памяти и эффективности вызова сами по себе).
Часто используемая хитрость заключается в том, что вы добавляете дополнительный параметр аккумулятор , который обрабатывает все ожидающие данные.Так как это может сделать рекурсивную функцию менее пригодной для использования, это обычно делается отдельно, так что пользователю вашей функции это кажется простым.
Так что в вашем примере это будет так, обычный 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 не ( пока ) использует преимущества хвостовой рекурсии,Другие языки программирования, такие как Scala и Kotlin.
Примечание: Path
обычно более мощный из старых File
, вам не нужно менять Path
на File
в вашем случае.