Java中有没有办法通过反射或一些很棒的API动态获取当前行号?就像异常发生时一样,行号在堆栈跟踪中打印出来,如下所示:
at weblogic.rmi.cluster.ClusterableRemoteRef.invoke(ClusterableRemoteRef.java:348)
Run Code Online (Sandbox Code Playgroud)
现在有没有办法在下面的代码中打印或记录?
log.error("Error in: " + this.getClass.getName() + "at line #"+ this.getClass.getActualLine());
Run Code Online (Sandbox Code Playgroud)
你可能会问,我为什么不简单地打印行号?好吧,因为代码可能会在特定的log.error()方法调用之前被删除或添加.
And*_*ter 41
您可以创建Throwable
并使用它StackTraceElements
:
System.err.println(new Throwable().getStackTrace()[0].getLineNumber());
Run Code Online (Sandbox Code Playgroud)
正如@Joachim所说,你也可以使用Thread.getStackTrace()
,例如喜欢
System.err.println(Thread.currentThread().getStackTrace()[1].getLineNumber());
Run Code Online (Sandbox Code Playgroud)
请注意,第二种方法返回一个稍微不同的数组 - 您需要使用索引为1的数组元素来获取当前行号,因为它包含对getStackTrace()
自身的调用作为第一个元素.
另请注意@Joachim的答案中关于记录和性能的评论.
Joa*_*uer 16
首先:如果有的话,那么日志模式(或者是layouter,或者你的日志框架调用那个部分的任何东西)应该这样做.代码中的记录器调用应该只写入实际的业务信息.有关记录器应添加的位置的信息.
下一步:获得这种操作很昂贵(就时间而言),因为Java没有针对此进行优化.在运行时,JVM需要检查其状态,加载/解析调试信息并找到与给定指令对应的行号.这就是为什么这种信息通常只是在发生异常时给出的原因(在这种情况下我们已经遇到问题并且知道花费的时间通常是值得的).
最后但并非最不重要:如果由于某种原因你需要自己的信息,你可以使用Thread.getStackTrace()
并检查第二个StackTraceElement
.
Bri*_*tei 10
我能够使用Thread.currentThread().getStackTrace()方法创建一组函数,这些函数一起工作以产生调用第一个方法的代码的行号,如下所示:
/** @return The line number of the code that ran this method
* @author Brian_Entei */
public static int getLineNumber() {
return ___8drrd3148796d_Xaf();
}
/** This methods name is ridiculous on purpose to prevent any other method
* names in the stack trace from potentially matching this one.
*
* @return The line number of the code that called the method that called
* this method(Should only be called by getLineNumber()).
* @author Brian_Entei */
private static int ___8drrd3148796d_Xaf() {
boolean thisOne = false;
int thisOneCountDown = 1;
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
for(StackTraceElement element : elements) {
String methodName = element.getMethodName();
int lineNum = element.getLineNumber();
if(thisOne && (thisOneCountDown == 0)) {
return lineNum;
} else if(thisOne) {
thisOneCountDown--;
}
if(methodName.equals("___8drrd3148796d_Xaf")) {
thisOne = true;
}
}
return -1;
}
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助!我将它们放在一个实用程序类中,以便它们不受影响,但仍然可以轻松访问.第二种方法是私有的,以防止除第一种方法之外的任何其他方法调用它,以便它始终正常工作.
从 JDK9 开始,您可以使用 StackWalker。与使用getStackTrace()
.
int get_line_number() {
return StackWalker.getInstance(StackWalker.Option.SHOW_HIDDEN_FRAMES).walk(
(s) -> s.skip(1).findFirst()).get().getLineNumber();
}
Run Code Online (Sandbox Code Playgroud)
我的直播可以做得更好,但我没有这方面的经验,而且我真的不喜欢直播,所以请随时编辑我的帖子以改进这部分。