場景:日誌埋點、AOP 切面、異常鏈路追蹤
C/C++ 有 __func__,Java 無關鍵字,需通過運行時棧獲取。
方式一:Thread.currentThread().getStackTrace()
public class Demo {
public void test() {
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
// stack[0] = getStackTrace()
// stack[1] = test() ← 當前方法
// stack[2] = 調用者
System.out.println("方法名: " + stack[1].getMethodName());
System.out.println("類名: " + stack[1].getClassName());
System.out.println("行號: " + stack[1].getLineNumber());
}
}
- 優點:不拋出異常,性能相對較好;
- 索引位置:[1] 為當前方法(JDK 8+ 穩定)。
方式二:new Throwable().getStackTrace()
public class Demo {
public void test() {
StackTraceElement[] stack = new Throwable().getStackTrace();
// stack[0] = test() ← 當前方法
System.out.println("方法名: " + stack[0].getMethodName());
System.out.println("類名: " + stack[0].getClassName());
}
}
- 優點:語義直觀,「拋出異常即捕獲棧」;
- 索引位置:[0] 為當前方法;
- 缺點:創建 Throwable 對象開銷略大,高頻調用慎用。
索引不穩定?JDK 版本差異實測
| JDK 版本 | Thread.getStackTrace() 當前方法索引 | Throwable.getStackTrace() 當前方法索引 |
| JDK 8 | 1 | 0 |
| JDK 11 | 1 | 0 |
| JDK 17 | 1 | 0 |
建議:單元測試驗證一次後硬編碼索引,或封裝工具類自動檢測:
public class StackUtil {
private static final int CURRENT_METHOD_INDEX_THREAD = detectThreadIndex();
private static final int CURRENT_METHOD_INDEX_THROWABLE = 0; // 固定
private static int detectThreadIndex() {
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
for (int i = 0; i < stack.length; i++) {
if ("detectThreadIndex".equals(stack[i].getMethodName())) return i + 1;
}
return 1; // fallback
}
public static String getCurrentMethodName() {
return Thread.currentThread().getStackTrace()[CURRENT_METHOD_INDEX_THREAD].getMethodName();
}
}
性能對比 (100萬次調用)
Thread.getStackTrace():~45 ms
new Throwable().getStackTrace():~120 ms
高頻場景(如每請求日誌)首選 Thread 方式;低頻場景(異常處理、啟動掃描)Throwable 更語義化。
- 上一篇文章: 堆排序 核心原理與 Java 手寫實現全解析
- 下一篇文章: Java MD5 工具類:字符串/字節數組雙重載、十六進制輸出
Copyright ©
程式碼之家 All Rights Reserved