Получение имени текущего исполняемого метода

Есть ли способ получить имя текущего исполняемого метода в Java?

Ответ 1

Thread.currentThread().getStackTrace() обычно содержит метод, из которого вы вызываете его, но есть подводные камни (см. Javadoc):

Некоторые виртуальные машины могут при некоторых обстоятельствах пропустить один или несколько стековых фреймов из трассировки стека. В крайнем случае виртуальной машине, у которой нет информации трассировки стека относительно этого потока, разрешено возвращать массив нулевой длины из этого метода.

Ответ 2

Технически это будет работать...

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

Однако во время компиляции будет создан новый анонимный внутренний класс (например, YourClass$1.class). Таким образом, это создаст файл .class для каждого метода, который развертывает этот трюк. Кроме того, в каждом вызове во время выполнения создается другой неиспользуемый экземпляр объекта. Таким образом, это может быть приемлемым отладочным трюком, но на него накладываются значительные накладные расходы.

Преимущество этого трюка заключается в том, что getEncosingMethod() возвращает java.lang.reflect.Method, который может использоваться для извлечения всей другой информации метода, включая аннотации и имена параметров. Это позволяет различать конкретные методы с одним и тем же именем (метод перегрузки).

Обратите внимание, что в соответствии с JavaDoc getEnclosingMethod() этот трюк не должен бросать SecurityException, поскольку внутренние классы должны быть загружены с использованием одного и того же загрузчика классов. Поэтому нет необходимости проверять условия доступа, даже если присутствует менеджер безопасности.

Для конструкторов требуется использовать getEnclosingConstructor(). Во время блоков вне (названных) методов getEnclosingMethod() возвращает null.

Ответ 3

Январь 2009:
Полный код будет (использовать с @Bombe caveat в виду):

/**
 * 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:

bluish комментарии:

Я использую JRE 6 и даю мне неправильное имя метода.
Он работает, если я пишу ste[2 + depth].getMethodName().

  • 0 - getStackTrace(),
  • 1 - getMethodName(int depth) и
  • 2 вызывает метод.

virgo47 answer (upvoted) фактически вычисляет нужный индекс для применения, чтобы вернуться имя метода.

Ответ 4

Мы использовали этот код для смягчения потенциальной изменчивости индекса стека трассировки - теперь просто вызовите методName 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 не делает этого плохо.: -)

Ответ 5

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

имя будет иметь значение foo.

Ответ 6

Самый быстрый способ, который я нашел, заключается в следующем:

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). И сохраняет доступный метод в статической переменной.

Ответ 7

Оба этих параметра работают для меня с Java:

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

Или:

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

Ответ 8

Используйте следующий код:

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

Ответ 9

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

Ответ 10

Это расширение на ответ 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 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 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 + ")";
    }
}

Ответ 11

Чтобы получить имя метода, вызывающего текущий метод, который вы можете использовать:

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

Это работает как на моем MacBook, так и на моем Android-телефоне

Я также пробовал:

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

но Android вернет "getStackTrace" Я могу исправить это для Android с помощью

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

но затем я получаю неправильный ответ на своем MacBook

Ответ 12

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
    }
}

Ответ 13

Это можно сделать с помощью StackWalker начиная с Java 9.

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, который охотно создает массив для всего стека вызовов. Также см. JEP для получения дополнительной информации.

Ответ 14

String methodName =Thread.currentThread().getStackTrace()[1].getMethodName();
System.out.println("methodName = " + methodName);

Ответ 15

Альтернативный метод - создать, но не выбросить исключение, и использовать тот объект, из которого можно получить данные трассировки стека, так как метод размещения обычно будет иметь индекс 0 - так долго поскольку JVM хранит эту информацию, как упоминалось выше. Однако это не самый дешевый метод.

От Throwable.getStackTrace() (это было то же самое, что и Java 5):

Нулевой элемент массива (при условии, что длина массива отлична от нуля) представляет верхнюю часть стека, которая является последним вызовом метода в последовательности. Обычно, это та точка, в которой этот throwable был создан и выброшен.

В приведенном ниже фрагменте предполагается, что класс не статический (из-за getClass()), но в стороне.

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

Ответ 16

У меня есть решение, использующее это (в 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())}));
    }
}

Ответ 17

Я не знаю, в чем заключается намерение получить текущее имя метода, но если это только для цели отладки, то здесь могут помочь такие фреймворки, как "logback". Например, в logback все, что вам нужно сделать, это использовать шаблон "% M" в конфигурации ведения журнала. Однако это следует использовать с осторожностью, так как это может ухудшить производительность.

Ответ 18

На всякий случай метод, имя которого вы хотите знать, это метод junit test, тогда вы можете использовать правило JNitit TestName: fooobar.com/questions/34876/...

Ответ 19

Я немного переписал ответ Маклеменца:

private static Method m;

static {
    try {
        m = Throwable.class.getDeclaredMethod(
            "getStackTraceElement",
            int.class
        );
    }
    catch (final NoSuchMethodException e) {
        throw new NoSuchMethodUncheckedException(e);
    }
    catch (final SecurityException e) {
        throw new SecurityUncheckedException(e);
    }
}


public static String getMethodName(int depth) {
    StackTraceElement element;

    final boolean accessible = m.isAccessible();
    m.setAccessible(true);

    try {
        element = (StackTraceElement) m.invoke(new Throwable(), 1 + depth);
    }
    catch (final IllegalAccessException e) {
        throw new IllegalAccessUncheckedException(e);
    }
    catch (final InvocationTargetException e) {
        throw new InvocationTargetUncheckedException(e);
    }
    finally {
        m.setAccessible(accessible);
    }

    return element.getMethodName();
}

public static String getMethodName() {
    return getMethodName(1);
}

Ответ 20

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

Ответ 21

Что не так с этим подходом:

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