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 classTest {2 public static voidmain(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 voidfoo() {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 voidbar() {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 classTest {2 public static voidmain(String args[]) {3 System.out.println(Thread.currentThread().getStackTrace()[1].getFileName() + ":" + Thread.currentThread().getStackTrace()[1].getLineNumber());4 foo();5 }6 static voidfoo() {7 System.out.println(Thread.currentThread().getStackTrace()[1].getFileName() + ":" + Thread.currentThread().getStackTrace()[1].getLineNumber());8 bar();9 }10 static voidbar() {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 classTest {2 public static voidmain(String args[]) {3 System.out.println(__FILE__() + ":" +__LINE__());4 foo();5 }6 static voidfoo() {7 System.out.println(__FILE__() + ":" +__LINE__());8 bar();9 }10 static voidbar() {11 System.out.println(__FILE__() + ":" +__LINE__());12 }13 staticString __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
参考: