首页 文章

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

提问于
浏览
420

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

20 回答

  • 4

    使用以下代码:

    StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
        StackTraceElement e = stacktrace[1];//coz 0th will be getStackTrace so 1st
        String methodName = e.getMethodName();
        System.out.println(methodName);
    
  • 2
    public static String getCurrentMethodName() {
            return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName();
        }
    
  • 15

    这两个选项都适用于Java:

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

    要么:

    Thread.currentThread().getStackTrace()[1].getMethodName()
    
  • 133

    Thread.currentThread().getStackTrace() 通常会包含您调用它的方法,但存在缺陷(请参阅Javadoc):

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

  • 13

    从技术上讲,这将有效......

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

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

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

    请注意,根据 getEnclosingMethod() 的JavaDoc,这个技巧不应该抛出 SecurityException ,因为内部类应该使用相同的类加载器加载 . 因此,即使存在安全管理器,也无需检查访问条件 .

    需要使用 getEnclosingConstructor() 作为构造函数 . 在(命名)方法之外的块期间, getEnclosingMethod() 返回 null .

  • 3

    2009年1月:
    完整的代码将是(与@Bombe's caveat一起使用):

    /**
     * Get the method name for a depth in call stack. 
    * 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 }

    更多this question .

    2011年12月更新:

    bluish评论:

    我使用JRE 6并给出了错误的方法名称 . 如果我写ste [2 depth] .getMethodName(),它就有效 . 0是getStackTrace(),1是getMethodName(int深度),2是调用方法 .

    virgo47answer(upvoted)实际上计算要应用的正确索引以便返回方法名称 .

  • 42

    我们使用此代码来缓解堆栈跟踪索引中的潜在可变性 - 现在只需调用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不会那么糟糕 . :-)

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

    名称将具有值foo .

  • 29

    The fastest way 我发现是:

    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存储在静态变量中 .

  • 2

    这是virgo47's answer(上图)的扩展 .

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

    /* 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 + ")";
        }
    }
    
  • 3

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

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

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

    我也尝试过:

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

    但Android将返回“getStackTrace”我可以用Android修复此问题

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

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

  • 10

    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
        }
    }
    
  • -5
    String methodName =Thread.currentThread().getStackTrace()[1].getMethodName();
    System.out.println("methodName = " + methodName);
    
  • 1

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

    来自Throwable.getStackTrace()(至少从Java 5开始):

    数组的第0个元素(假设数组的长度为非零)表示堆栈的顶部,这是序列中的最后一个方法调用 . 通常,这是创建和抛出此throwable的点 .

    下面的代码段假设该类是非静态的(因为getClass()),但这是一个旁边 .

    System.out.printf("Class %s.%s\n", getClass().getName(), new Exception("is not thrown").getStackTrace()[0].getMethodName());
    
  • 161

    我有解决方案使用此功能(在Android中)

    /**
     * @param className       fully qualified className
     *                        
    * <code>YourClassName.class.getName();</code> *

    * @param classSimpleName simpleClassName *
    * <code>YourClassName.class.getSimpleName();</code> *

    */ 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())})); } }
  • 12

    我没有't know what is the intention behind getting the currently executed method'的名字,但如果那只是为了调试目的,那么像"logback"这样的日志框架可以在这里提供帮助 . 例如,在logback中,您需要做的就是use the pattern "%M" in your logging configuration . 但是,应谨慎使用,因为这可能会降低性能 .

  • 283

    以防万一的方法您想知道的名称是junit测试方法,然后您可以使用junit TestName规则:https://stackoverflow.com/a/1426730/3076107

  • 27

    从Java 9开始,这可以使用StackWalker来完成 .

    public static String getCurrentMethodName() {
        return StackWalker.getInstance()
                          .walk(s -> s.skip(1).findFirst())
                          .get()
                          .getMethodName();
    }
    
    public static String getCallerMethodName() {
        return StackWalker.getInstance()
                          .walk(s -> s.skip(2).findFirst())
                          .get()
                          .getMethodName();
    }
    

    StackWalker 被设计为懒惰,因此它可能比 Thread.getStackTrace 更有效,它急切地为整个callstack创建一个数组 . Also see the JEP for more information.

  • 82
    MethodHandles.lookup().lookupClass().getEnclosingMethod().getName();
    
  • 25

    这种方法有什么问题:

    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(...) 而疯狂之前,您可以随时创建一些方法,以便可以重定向输出,例如:

    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());
            }
        }
    

相关问题