首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java 異常堆疊追蹤:精確定位拋出異常的程式碼行號

     編輯:程式設計綜合問答

標準做法:Throwable.printStackTrace() / getStackTrace()

try {
    // 業務代碼
} catch (Exception e) {
    // 1. 列印完整堆疊到標準錯誤流 (含行號)
    e.printStackTrace();

    // 2. 程式化取得 StackTraceElement 陣列
    StackTraceElement[] elements = e.getStackTrace();
    if (elements.length > 0) {
        StackTraceElement top = elements[0]; // 棧頂 = 拋出異常的那一行
        System.out.println("異常類別: " + top.getClassName());
        System.out.println("異常方法: " + top.getMethodName());
        System.out.println("檔案名稱: " + top.getFileName());
        System.out.println("行號: " + top.getLineNumber()); // 關鍵:原始碼行號
    }
}

行號顯示的前置條件

  • 編譯時保留行號資訊: javac -g (預設開啟) 或 javac -g:lines,vars,source。勿使用 -g:none。
  • 執行時未被混淆/優化移除: ProGuard/R8 混淆時需保留 -keepattributes SourceFile,LineNumberTable (見 Android 混淆配置)。
  • JIT 編譯內聯: 极熱點方法可能被內聯導致堆疊摺疊,行號顯示為 -1 或非預期值。可用 -XX:-Inline 關閉內聯除錯 (僅開發環境)。

特殊情況:只定位到方法、無行號

若 getLineNumber() 回傳 -1 或堆疊僅顯示方法名,可能原因:

  1. Class 檔案編譯時未包含 LineNumberTable 屬性 (如某些舊版編譯器或特殊編譯參數)。
  2. 異常為 Native Method (JNI 層拋出),Java 層無行號資訊。
  3. 使用 lambda / method reference 產生的合成類別,行號對應原始碼可能偏移。

進階技巧:自訂異常攔截與日誌格式化

// 統一異常處理器 (Spring @ControllerAdvice / Thread.setDefaultUncaughtExceptionHandler)
public class GlobalExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    public void handle(Throwable t) {
        StringWriter sw = new StringWriter();
        t.printStackTrace(new PrintWriter(sw));
        String stack = sw.toString();

        // 取得最頂層業務代碼行 (過濾框架堆疊)
        StackTraceElement[] st = t.getStackTrace();
        String bizLocation = "Unknown";
        for (StackTraceElement el : st) {
            if (el.getClassName().startsWith("com.mycompany.")) {
                bizLocation = el.getClassName() + "." + el.getMethodName() + ":" + el.getLineNumber();
                break;
            }
        }
        log.error("異常: {} | 業務定位: {} | 完整堆疊:\n{}", t.getMessage(), bizLocation, stack);
    }
}

總結

「拋出異常的那一行」正是 e.getStackTrace()[0] (或 printStackTrace() 第一行 at ...) 所指示的位置。確保編譯保留行號、混淆保留 LineNumberTable,即可在生產環境精確定位錯誤源頭。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved