public static void listTree(File root) {
listTree(root, 0);
}
private static void listTree(File node, int level) {
String indent = "----".repeat(level); // Java 11+
System.out.println(indent + node.getName());
if (!node.isDirectory()) return;
File[] children = node.listFiles();
if (children == null) return; // 權限不足或 IO 錯誤
for (File child : children) {
listTree(child, level + 1);
}
}
遞歸本質是棧幀的壓入與彈出:
multiply(5)
→ 5 * multiply(4)
→ 4 * multiply(3)
→ 3 * multiply(2)
→ 2 * multiply(1)
→ 1 (基線條件)
← 2 * 1 = 2
← 3 * 2 = 6
← 4 * 6 = 24
← 5 * 24 = 120
每層調用在棧中保存局部變量(n、factorial),基線條件觸發後逐層回溯計算。
iload_0:載入參數 nif_icmpeq / ifne:基線條件判斷invokestatic:遞歸調用自身imul / istore_1:乘法並存儲結果ireturn:返回結果給上層// 迭代版:無棧溢出風險,適合深層目錄
public static void listTreeIterative(File root) {
Deque<File> stack = new ArrayDeque<>();
stack.push(root);
while (!stack.isEmpty()) {
File cur = stack.pop();
System.out.println(cur.getName());
if (cur.isDirectory()) {
File[] kids = cur.listFiles();
if (kids != null) {
// 逆序入棧保持原序輸出
for (int i = kids.length - 1; i >= 0; i--) stack.push(kids[i]);
}
}
}
}
Files.walkFileTree(root.toPath(), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
System.out.println(file.getFileName());
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
log.warn("無法訪問: {}", file, exc);
return FileVisitResult.CONTINUE; // 跳過錯誤繼續
}
});
優勢:自動處理符號鏈接、權限錯誤、大文件系統性能優化、支持並行流(Files.find)。
private static final int MAX_DEPTH = 1000;
private static void safeList(File node, int depth) {
if (depth > MAX_DEPTH) throw new IllegalStateException("目錄層級過深,疑似循環鏈接");
...
}
listFiles() 返回 null 而非空數組(無權限、非目錄、IO 錯誤)Set<File> visited 去重StackOverflowError,必須用迭代或 NIO.2理解遞歸棧機制,選對工具(NIO.2 > 迭代 > 遞歸),才能寫出健壯的文件系統遍歷代碼。