掃描專案目錄下所有 `.java` 檔案,統計四類行數:
import java.io.*;
import java.nio.file.*;
import java.util.concurrent.atomic.AtomicLong;
public class CodeLineCounter {
private final AtomicLong totalLines = new AtomicLong();
private final AtomicLong codeLines = new AtomicLong();
private final AtomicLong commentLines = new AtomicLong();
private final AtomicLong blankLines = new AtomicLong();
public static void main(String[] args) throws IOException {
String rootPath = args.length > 0 ? args[0] : System.getProperty("user.dir");
CodeLineCounter counter = new CodeLineCounter();
counter.scan(Paths.get(rootPath));
counter.printReport();
}
public void scan(Path root) throws IOException {
Files.walkFileTree(root, new SimpleFileVisitor() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (file.toString().endsWith(".java")) {
countFile(file);
}
return FileVisitResult.CONTINUE;
}
});
}
private void countFile(Path file) {
try (BufferedReader br = Files.newBufferedReader(file, java.nio.charset.StandardCharsets.UTF_8)) {
boolean inBlockComment = false;
String line;
while ((line = br.readLine()) != null) {
totalLines.incrementAndGet();
String trimmed = line.trim();
// 空白行
if (trimmed.isEmpty()) {
blankLines.incrementAndGet();
continue;
}
// 處理區塊註解狀態
if (inBlockComment) {
commentLines.incrementAndGet();
if (trimmed.endsWith("*/")) inBlockComment = false;
continue;
}
// 單行註解
if (trimmed.startsWith("//")) {
commentLines.incrementAndGet();
continue;
}
// 區塊註解開始
if (trimmed.startsWith("/*")) {
commentLines.incrementAndGet();
if (!trimmed.endsWith("*/")) inBlockComment = true; // 跨行
continue;
}
// 正常程式碼行 (可能包含行尾註解,這裡簡單計為程式碼)
codeLines.incrementAndGet();
}
} catch (IOException e) {
System.err.println("讀取失敗: " + file + " - " + e.getMessage());
}
}
private void printReport() {
System.out.println("================== 程式碼統計報表 ==================");
System.out.printf("掃描目錄: %s%n", System.getProperty("user.dir"));
System.out.printf("總行數 : %,d%n", totalLines.get());
System.out.printf("程式碼行 : %,d%n", codeLines.get());
System.out.printf("註解行 : %,d%n", commentLines.get());
System.out.printf("空白行 : %,d%n", blankLines.get());
System.out.println("==================================================");
long sum = codeLines.get() + commentLines.get() + blankLines.get();
System.out.printf("驗證總和 : %,d (差異: %,d)%n", sum, totalLines.get() - sum);
}
}
# 編譯
javac CodeLineCounter.java
# 執行 (掃描當前目錄)
java CodeLineCounter
# 指定目錄
java CodeLineCounter /path/to/project/src
================== 程式碼統計報表 ================== 掃描目錄: /home/user/my-project 總行數 : 125,430 程式碼行 : 78,210 註解行 : 22,150 空白行 : 25,070 ================================================== 驗證總和 : 125,430 (差異: 0)
| 項目 | 處理方式 | 已知限制 |
|---|---|---|
| 單行註解 // | trim() 後 startsWith("//") | 字串字面值內的 // 會誤判 |
| 多行註解 /* */ | 狀態機 inBlockComment | 巢狀註解不支援 (Java 不允許) |
| Javadoc /** */ | 同多行註解處理 | 同上 |
| 字串/字元常值 | 未剝離,可能誤判裡面的註解符號 | 需完整語法分析器 (如 JavaParser) 解決 |
| 編碼 | 預設 UTF-8 | 舊專案可能為 GBK/Big5,需自行調整 |