获取当前正在执行的方法的名称

有没有办法在Java中获取当前正在执行的方法的名称?

ThreadcurrentThread()getStackTrace()通常包含你调用它的方法,但是有缺陷(参见Javadoc ):

某些虚拟机在某些情况下可能会忽略堆栈跟踪中的一个或多个堆栈帧。 在极端的情况下,一个没有关于这个线程的堆栈跟踪信息的虚拟机被允许从这个方法返回一个长度为零的数组。

技术上这将工作…

 String name = new Object(){}.getClass().getEnclosingMethod().getName(); 

但是,在编译期间会创build一个新的匿名内部类(例如YourClass$1.class )。 所以这将为每个部署这个技巧的方法创build一个.class文件。 此外,在运行时每次调用时都会创build一个未使用的对象实例。 所以这可能是一个可以接受的debugging技巧,但确实带来了大量的开销。

这个技巧的优点是getEncosingMethod()返回java.lang.reflect.Method ,它可以用来检索方法的所有其他信息,包括注释和参数名称。 这使得可以区分具有相同名称的特定方法(方法过载)。

请注意,根据getEnclosingMethod()的JavaDoc,这个技巧不应该抛出SecurityException因为内部类应该使用相同的类加载器加载。 所以即使安全pipe理员在场,也不需要检查访问条件。

需要为构造函数使用getEnclosingConstructor() 。 在(named)方法之外的块中, getEnclosingMethod()返回null

2009年1月:
一个完整的代码将(与@ Bombe的注意事项一起使用):

 /** * Get the method name for a depth in call stack. <br /> * Utility function * @param depth depth in the call stack (0 means current method, 1 means call method, ...) * @return method name */ public static String getMethodName(final int depth) { final StackTraceElement[] ste = Thread.currentThread().getStackTrace(); //System. out.println(ste[ste.length-depth].getClassName()+"#"+ste[ste.length-depth].getMethodName()); // return ste[ste.length - depth].getMethodName(); //Wrong, fails for depth = 0 return ste[ste.length - 1 - depth].getMethodName(); //Thank you Tom Tresansky } 

在这个问题更多。

2011年12月更新:

偏蓝的评论:

我使用JRE 6并给了我不正确的方法名称。
它工作,如果我写ste[2 + depth].getMethodName().

  • 0getStackTrace()
  • 1getMethodName(int depth)
  • 2是调用方法。

virgo47的答案 (upvoted)实际上是计算正确的索引以便取回方法名称。

我们使用这个代码来缓解堆栈跟踪索引中的潜在可变性 – 现在只需调用methodName util:

 public class MethodNameTest { private static final int CLIENT_CODE_STACK_INDEX; static { // Finds out the index of "this code" in the returned stack trace - funny but it differs in JDK 1.5 and 1.6 int i = 0; for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { i++; if (ste.getClassName().equals(MethodNameTest.class.getName())) { break; } } CLIENT_CODE_STACK_INDEX = i; } public static void main(String[] args) { System.out.println("methodName() = " + methodName()); System.out.println("CLIENT_CODE_STACK_INDEX = " + CLIENT_CODE_STACK_INDEX); } public static String methodName() { return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX].getMethodName(); } } 

似乎过度工程,但我们有一些JDK 1.5的固定数量,当我们转移到JDK 1.6时,它有点惊讶。 现在在Java 6/7中是一样的,但你永远不知道。 在运行期间这个索引没有改变,但希望HotSpot不会那么糟糕。 🙂

  public class SomeClass { public void foo(){ class Local {}; String name = Local.class.getEnclosingMethod().getName(); } } 

名字将有价值foo。

我发现最快的方法是:

 import java.lang.reflect.Method; public class TraceHelper { // save it static to have it available on every call private static Method m; static { try { m = Throwable.class.getDeclaredMethod("getStackTraceElement", int.class); m.setAccessible(true); } catch (Exception e) { e.printStackTrace(); } } public static String getMethodName(final int depth) { try { StackTraceElement element = (StackTraceElement) m.invoke( new Throwable(), depth + 1); return element.getMethodName(); } catch (Exception e) { e.printStackTrace(); return null; } } } 

它直接访问本地方法getStackTraceElement(int depth)。 并将可访问的Method存储在一个静态variables中。

使用下面的代码:

  StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace(); StackTraceElement e = stacktrace[1];//coz 0th will be getStackTrace so 1st String methodName = e.getMethodName(); System.out.println(methodName); 

这两个选项对我来说都适用于Java:

 new Object(){}.getClass().getEnclosingMethod().getName() 

要么:

 Thread.currentThread().getStackTrace()[1].getMethodName() 
 public static String getCurrentMethodName() { return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName(); } 

这是Virgo47答案的扩展(上图)。

它提供了一些静态方法来获取当前的和调用的类/方法名称。

 /* Utility class: Getting the name of the current executing method * https://stackoverflow.com/questions/442747/getting-the-name-of-the-current-executing-method * * Provides: * * getCurrentClassName() * getCurrentMethodName() * getCurrentFileName() * * getInvokingClassName() * getInvokingMethodName() * getInvokingFileName() * * Nb. Using StackTrace's to get this info is expensive. There are more optimised ways to obtain * method names. See other stackoverflow posts eg. https://stackoverflow.com/questions/421280/in-java-how-do-i-find-the-caller-of-a-method-using-stacktrace-or-reflection/2924426#2924426 * * 29/09/2012 (lem) - added methods to return (1) fully qualified names and (2) invoking class/method names */ package com.stackoverflow.util; public class StackTraceInfo { /* (Lifted from virgo47's stackoverflow answer) */ private static final int CLIENT_CODE_STACK_INDEX; static { // Finds out the index of "this code" in the returned stack trace - funny but it differs in JDK 1.5 and 1.6 int i = 0; for (StackTraceElement ste: Thread.currentThread().getStackTrace()) { i++; if (ste.getClassName().equals(StackTraceInfo.class.getName())) { break; } } CLIENT_CODE_STACK_INDEX = i; } public static String getCurrentMethodName() { return getCurrentMethodName(1); // making additional overloaded method call requires +1 offset } private static String getCurrentMethodName(int offset) { return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getMethodName(); } public static String getCurrentClassName() { return getCurrentClassName(1); // making additional overloaded method call requires +1 offset } private static String getCurrentClassName(int offset) { return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getClassName(); } public static String getCurrentFileName() { return getCurrentFileName(1); // making additional overloaded method call requires +1 offset } private static String getCurrentFileName(int offset) { String filename = Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getFileName(); int lineNumber = Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + offset].getLineNumber(); return filename + ":" + lineNumber; } public static String getInvokingMethodName() { return getInvokingMethodName(2); } private static String getInvokingMethodName(int offset) { return getCurrentMethodName(offset + 1); // re-uses getCurrentMethodName() with desired index } public static String getInvokingClassName() { return getInvokingClassName(2); } private static String getInvokingClassName(int offset) { return getCurrentClassName(offset + 1); // re-uses getCurrentClassName() with desired index } public static String getInvokingFileName() { return getInvokingFileName(2); } private static String getInvokingFileName(int offset) { return getCurrentFileName(offset + 1); // re-uses getCurrentFileName() with desired index } public static String getCurrentMethodNameFqn() { return getCurrentMethodNameFqn(1); } private static String getCurrentMethodNameFqn(int offset) { String currentClassName = getCurrentClassName(offset + 1); String currentMethodName = getCurrentMethodName(offset + 1); return currentClassName + "." + currentMethodName ; } public static String getCurrentFileNameFqn() { String CurrentMethodNameFqn = getCurrentMethodNameFqn(1); String currentFileName = getCurrentFileName(1); return CurrentMethodNameFqn + "(" + currentFileName + ")"; } public static String getInvokingMethodNameFqn() { return getInvokingMethodNameFqn(2); } private static String getInvokingMethodNameFqn(int offset) { String invokingClassName = getInvokingClassName(offset + 1); String invokingMethodName = getInvokingMethodName(offset + 1); return invokingClassName + "." + invokingMethodName; } public static String getInvokingFileNameFqn() { String invokingMethodNameFqn = getInvokingMethodNameFqn(2); String invokingFileName = getInvokingFileName(2); return invokingMethodNameFqn + "(" + invokingFileName + ")"; } } 

要获取调用当前方法的方法的名称,您可以使用:

 new Exception("is not thrown").getStackTrace()[1].getMethodName() 

这适用于我的MacBook以及我的Android手机

我也试过:

 Thread.currentThread().getStackTrace()[1] 

但Android将返回“getStackTrace”我可以解决这个Android的

 Thread.currentThread().getStackTrace()[2] 

但后来我在我的MacBook上得到了错误的答案

Util.java:

 public static String getCurrentClassAndMethodNames() { final StackTraceElement e = Thread.currentThread().getStackTrace()[2]; final String s = e.getClassName(); return s.substring(s.lastIndexOf('.') + 1, s.length()) + "." + e.getMethodName(); } 

SomeClass.java:

 public class SomeClass { public static void main(String[] args) { System.out.println(Util.getCurrentClassAndMethodNames()); // output: SomeClass.main } } 

另一种方法是创build但不抛出exception,并使用该对象从中获取堆栈跟踪数据,因为封闭方法通常在索引0处 – 只要JVM存储该信息,就像其他人一样上文提到的。 然而,这不是最便宜的方法。

从Throwable.getStackTrace() (至less从Java 5开始,这一直是相同的):

数组的第零个元素(假设数组的长度不为零)表示堆栈的顶部,这是序列中最后一个方法调用。 通常 ,这是这个throwable被创build和抛出的地方。

下面的代码片段假定这个类是非静态的(因为getClass()),但这是一个问题。

 System.out.printf("Class %s.%s\n", getClass().getName(), new Exception("is not thrown").getStackTrace()[0].getMethodName()); 
 String methodName =Thread.currentThread().getStackTrace()[1].getMethodName(); System.out.println("methodName = " + methodName); 

我有解决这个问题(在Android中)

 /** * @param className fully qualified className * <br/> * <code>YourClassName.class.getName();</code> * <br/><br/> * @param classSimpleName simpleClassName * <br/> * <code>YourClassName.class.getSimpleName();</code> * <br/><br/> */ public static void getStackTrace(final String className, final String classSimpleName) { final StackTraceElement[] steArray = Thread.currentThread().getStackTrace(); int index = 0; for (StackTraceElement ste : steArray) { if (ste.getClassName().equals(className)) { break; } index++; } if (index >= steArray.length) { // Little Hacky Log.w(classSimpleName, Arrays.toString(new String[]{steArray[3].getMethodName(), String.valueOf(steArray[3].getLineNumber())})); } else { // Legitimate Log.w(classSimpleName, Arrays.toString(new String[]{steArray[index].getMethodName(), String.valueOf(steArray[index].getLineNumber())})); } } 

我不知道获取当前执行的方法名称的意图是什么,但是如果这仅仅是为了debugging目的,那么像“logback”这样的日志框架可以在这里帮助。 例如,在logback中,您只需在日志loggingconfiguration中使用模式“%M” 。 但是,这应该谨慎使用,因为这可能会降低性能。

 MethodHandles.lookup().lookupClass().getEnclosingMethod().getName(); 

这种方法有什么问题:

 class Example { FileOutputStream fileOutputStream; public Example() { //System.out.println("Example.Example()"); debug("Example.Example()",false); // toggle try { fileOutputStream = new FileOutputStream("debug.txt"); } catch (Exception exception) { debug(exception + Calendar.getInstance().getTime()); } } private boolean was911AnInsideJob() { System.out.println("Example.was911AnInsideJob()"); return true; } public boolean shouldGWBushBeImpeached(){ System.out.println("Example.shouldGWBushBeImpeached()"); return true; } public void setPunishment(int yearsInJail){ debug("Server.setPunishment(int yearsInJail=" + yearsInJail + ")",true); } } 

在人们疯狂地使用System.out.println(...)你总是可以创build一些方法,以便输出可以被redirect,例如:

  private void debug (Object object) { debug(object,true); } private void dedub(Object object, boolean debug) { if (debug) { System.out.println(object); // you can also write to a file but make sure the output stream // ISN'T opened every time debug(Object object) is called fileOutputStream.write(object.toString().getBytes()); } }