Получение имени текущего выполняемого метода - PullRequest
433 голосов
/ 14 января 2009

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

Ответы [ 20 ]

291 голосов
/ 05 мая 2011

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

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

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

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

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

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

164 голосов
/ 14 января 2009

<a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Thread.html" rel="nofollow noreferrer">Thread</a>.<a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Thread.html#currentThread()" rel="nofollow noreferrer">currentThread()</a>.<a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Thread.html#getStackTrace()" rel="nofollow noreferrer">getStackTrace()</a> обычно содержит метод, из которого вы его вызываете, но есть подводные камни (см. Javadoc ):

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

134 голосов
/ 14 января 2009

Январь 2009:
Полный код будет (использовать с учетом @ предостережения Бомбе ):

/**
 * 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 года:

голубоватый комментарии:

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

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

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

82 голосов
/ 21 декабря 2011

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

44 голосов
/ 13 марта 2013
 public class SomeClass {
   public void foo(){
      class Local {};
      String name = Local.class.getEnclosingMethod().getName();
   }
 }

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

30 голосов
/ 01 сентября 2015

Оба эти варианта работают у меня с Java:

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

Или:

Thread.currentThread().getStackTrace()[1].getMethodName()
30 голосов
/ 30 июля 2012

Самый быстрый способ Я обнаружил, что:

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

25 голосов
/ 12 июня 2012

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

    StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
    StackTraceElement e = stacktrace[1];//coz 0th will be getStackTrace so 1st
    String methodName = e.getMethodName();
    System.out.println(methodName);
15 голосов
/ 19 февраля 2014
public static String getCurrentMethodName() {
        return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName();
    }
13 голосов
/ 29 сентября 2012

Это расширение для ответа virgo47 (выше).

Предоставляет некоторые статические методы для получения текущих и вызывающих имен классов / методов.

/* Utility class: Getting the name of the current executing method 
 * /255593/poluchenie-imeni-tekuschego-vypolnyaemogo-metoda
 * 
 * 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 + ")";
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...