动态获取当前行号

Java中有没有办法通过reflection或一些很棒的API动态获取当前行号? 就像exception发生时一样,行号在堆栈跟踪中打印出来,如下所示:

at weblogic.rmi.cluster.ClusterableRemoteRef.invoke(ClusterableRemoteRef.java:348) 

现在有没有办法在下面的代码中打印或记录?

 log.error("Error in: " + this.getClass.getName() + "at line #"+ this.getClass.getActualLine()); 

你可能会问,我为什么不简单地打印行号? 好吧,因为代码可能会在特定的log.error()方法调用之前被删除或添加。

我能够使用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; } 

希望这可以帮助! 我将它们放在一个实用程序类中,以便它们不受影响,但仍然可以轻松访问。 第二种方法是私有的,以防止除第一种方法之外的任何其他方法调用它,以便它始终正常工作。

您可以创建一个Throwable并使用它的StackTraceElements

  System.err.println(new Throwable().getStackTrace()[0].getLineNumber()); 

正如@Joachim所说,你也可以使用Thread.getStackTrace() ,例如

  System.err.println(Thread.currentThread().getStackTrace()[1].getLineNumber()); 

请注意,第二种方法返回一个稍微不同的数组 – 您需要使用索引为1的数组元素来获取当前行号,因为它包含对getStackTrace()本身作为第一个元素的调用。

另请注意@Joachim的答案中有关记录和性能的评论。

首先:如果有的话 ,那么日志模式(或者是layouter,或者你的日志框架调用那个部分的任何东西)都应该这样做。 代码中的记录器调用应该写出实际的业务信息。 有关记录器应添加的位置的信息。

下一步:获得这种操作是昂贵的(就时间而言),因为Java没有针对此进行优化。 在运行时,JVM需要检查其状态,加载/解析调试信息并找到与给定指令对应的行号。 这就是为什么这种信息通常只是在发生exception时给出的原因(在这种情况下我们已经遇到问题,并且知道花费的时间通常是值得的)。

最后但并非最不重要: 如果由于某种原因你需要自己的信息,你可以使用Thread.getStackTrace()并检查它上面的第二个StackTraceElement

也可以使用以下代码段获取Exception行号 。 在util类中使用以下util方法。

  public static int getExceptionLineNumber(Exception e, String methodNameExp) { StackTraceElement ele = Arrays.stream(e.getStackTrace()).filter(o -> o.getMethodName().equals(methodNameExp)).findAny().orElse(null); if(ele != null){ return ele.getLineNumber(); } return -1; } 

从catch块你可以调用如下:

 catch (Exception e){ logger.info("Exception line number "+ Util.getExceptionLineNumber(e, new Object(){}.getClass().getEnclosingMethod().getName())); } 

希望这个有效! 🙂