Java代碼中如何獲文件名和行號等源碼信息?


C語言中有__FILE__、__LINE__等預定義宏,用於獲取當前文件名和行號等信息,而且它們的值在預處理時就已經確定了,不會占用運行時時間去計算,這對打印日志相當有用。那么,Java語言是否也有類似的功能呢?

Java是否提供某種方法:可以讓用戶代碼在編譯時確定源碼行號等信息,本人暫時不知曉。不過從網上搜索得到的方法大致是:

  • Thread.currentThread().getStackTrace()[1].getFileName():獲取當前文件名;
  • Thread.currentThread().getStackTrace()[1].getLineNumber():獲取當前行號。

其中:Thread.currentThread().getStackTrace()返回的是一個數組形式的函數調用棧(棧頂在索引0處),其中第1個元素(索引為0)為最新調用的函數信息(getStackTrace()),第2個元素(索引為1)為當前函數(即調用getStackTrace()的函數)信息。示例:

 1 public class Test {
 2     public static void main(String args[]) {
 3         StackTraceElement[] stack = Thread.currentThread().getStackTrace();
 4         for (int i = 0; i < stack.length; ++i)
 5             System.out.println(stack[i].getFileName() + ":" + stack[i].getLineNumber() + ": " + stack[i].getMethodName());
 6         System.out.println("");
 7         foo();
 8     }
 9     static void foo() {
10         StackTraceElement[] stack = Thread.currentThread().getStackTrace();
11         for (int i = 0; i < stack.length; ++i)
12             System.out.println(stack[i].getFileName() + ":" + stack[i].getLineNumber() + ": " + stack[i].getMethodName());
13         System.out.println("");
14         bar();
15     }
16     static void bar() {
17         StackTraceElement[] stack = Thread.currentThread().getStackTrace();
18         for (int i = 0; i < stack.length; ++i)
19             System.out.println(stack[i].getFileName() + ":" + stack[i].getLineNumber() + ": " + stack[i].getMethodName());
20     }
21 }

輸出:

$ javac Test.java
$ java Test
null:-1: getStackTrace
Test.java:3: main

null:-1: getStackTrace
Test.java:10: foo
Test.java:7: main

null:-1: getStackTrace
Test.java:17: bar
Test.java:14: foo
Test.java:7: main

於是,如果我們想在日志中打印當前文件名和行號,就可以:

 1 public class Test {
 2     public static void main(String args[]) {
 3         System.out.println(Thread.currentThread().getStackTrace()[1].getFileName() + ":" + Thread.currentThread().getStackTrace()[1].getLineNumber());
 4         foo();
 5     }
 6     static void foo() {
 7         System.out.println(Thread.currentThread().getStackTrace()[1].getFileName() + ":" + Thread.currentThread().getStackTrace()[1].getLineNumber());
 8         bar();
 9     }
10     static void bar() {
11         System.out.println(Thread.currentThread().getStackTrace()[1].getFileName() + ":" + Thread.currentThread().getStackTrace()[1].getLineNumber());
12     }
13 }

輸出:

$ javac Test.java
$ java Test
Test.java:3
Test.java:7
Test.java:11

不過每次都要寫這么長的幾串代碼“Thread.currentThread().getStackTrace()[1].getXXX()”拼一起看起來難看敲起來也累。於是我們可以將getStackTrace()封裝到另一個函數中:

 1 public class Test {
 2     public static void main(String args[]) {
 3         System.out.println(__FILE__() + ":" + __LINE__());
 4         foo();
 5     }
 6     static void foo() {
 7         System.out.println(__FILE__() + ":" + __LINE__());
 8         bar();
 9     }
10     static void bar() {
11         System.out.println(__FILE__() + ":" + __LINE__());
12     }
13     static String __FILE__() {
14         return Thread.currentThread().getStackTrace()[2].getFileName();
15     }
16     static int __LINE__() {
17         return Thread.currentThread().getStackTrace()[2].getLineNumber();
18     }
19 }

輸出結果一樣:

$ javac Test.java
$ java Test
Test.java:3
Test.java:7
Test.java:11

參考:

  1. http://stackoverflow.com/questions/22677815/eclipse-println-line-does-such-a-preprocessor-macro-exist-to-program
  2. http://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#getStackTrace--
  3. http://docs.oracle.com/javase/8/docs/api/java/lang/StackTraceElement.html
  4. http://stackoverflow.com/questions/115008/how-can-we-print-line-numbers-to-the-log-in-java
  5. http://www.codeceo.com/article/8-java-log-framework.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM