Получение имени выполняемого в данный момент метода

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
487
0
399 342
22
Перейти к ответу Данный вопрос помечен как решенный

Ответы 22

Ответ принят как подходящий

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

Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace. In the extreme case, a virtual machine that has no stack trace information concerning this thread is permitted to return a zero-length array from this method.

Верна ли эта же ошибка для трассировки стека в исключениях?

Nate Parsons 03.03.2009 22:15

Да, это. Документация для Метательный. [GetStackTrace ()] (download.oracle.com/javase/1.5.0‌ / docs / api / java / lang / ‌… содержит точно такой же абзац.

Bombe 11.11.2011 20:50

В основе лежит то, что JVM - это не обязательный, чтобы иметь возможность обеспечивать трассировку стека, но большая работа была проделана для того, чтобы сделать HotSpot очень надежным. Однако вам нужно знать, если вы хотите, чтобы ваш код не зависел от поведения конкретной JVM.

Thorbjørn Ravn Andersen 15.04.2013 12:53

Версия Alexsmail ниже не создает трассировку стека и дает вам доступ к фактическому объекту метода, а не только к имени (так что вы также можете узнать тип возвращаемого значения). Я не отмечал стендовую маркировку, но подозреваю, что его метод намного быстрее, так как трассировки стека, как правило, дороги.

Gus 07.07.2013 01:48

Ответ Девина, кажется, дает гораздо более сжатый ответ на этот вопрос.

risingTide 03.02.2016 18:46

Январь 2009 г .:
Полный код будет (для использования с Предупреждение @ 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 г .:

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

I use JRE 6 and gives me incorrect method name.
It works if I write ste[2 + depth].getMethodName().

  • 0 is getStackTrace(),
  • 1 is getMethodName(int depth) and
  • 2 is invoking method.

отвечатьдева47 (проголосовало за) фактически вычисляет правильный индекс для применения, чтобы вернуть имя метода.

Для меня это говорит только «главное». : - /

Prof. Falken 25.05.2011 16:50

@Amigable: вы пытались распечатать весь массив StackTraceElement для целей отладки и проверить, действительно ли 'main' правильный метод?

VonC 25.05.2011 18:28

Я использую JRE 6 и даю неправильное имя метода. Работает, если я напишу ste[2 + depth].getMethodName(). 0 - это getStackTrace(), 1 - это getMethodName(int depth), а 2 - вызывающий метод. См. Также @ virgo47 ответ.

bluish 28.12.2011 17:15

@bluish: хороший момент. Я включил ваш комментарий и ссылку на ответ virgo47 в свой.

VonC 28.12.2011 20:01

@VonC Действительно ли эта реализация верна? глубина здесь должна быть ste.length + 1, чтобы указать текущий метод. Разве не должно быть ste [глубина + 1], если мы должны разрешить глубину = 0?

mmm 29.03.2020 18:35

@mmm Так было, когда я писал этот ответ одиннадцать много лет назад. Я упоминаю ответ virgo47 в моем собственном сообщении, и я поддержал ваш ответ.

VonC 29.03.2020 19:46

@VonC Хорошо, спасибо. По какой причине вы вместо этого не редактируете свой ответ? В некоторых случаях это правильно?

mmm 29.03.2020 21:39

@VonC Подождите, вы говорите, что JVM изменила реализацию и порядок трассировки стека в последних версиях JDK? Сначала я почувствовал, что моя память также сказала, что трассировки стека были перенесены. Теперь они сдвинуты. Странно, если это правда.

mmm 29.03.2020 21:40

@mmm Я просто говорю, что не помню точное окружение, когда писал это. Но я признал, что другие ответы более точны.

VonC 29.03.2020 21:57

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

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

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

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

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

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

Прокомментируйте, поддерживается ли это во всех JVM и что такого ограничения, аналогичного упущению Stacktrace, не существует.

Drupad Panchal 13.12.2011 20:00

Это не даст вам метода, который в настоящее время выполняется. Это даст вам тот метод, в котором определен анонимный / локальный класс. - docs.oracle.com/javase/6/docs/api/java/lang/…

shrini1000 04.05.2012 14:52

class Local {}; Имя строки = Local.class.getEnclosingMethod (). GetName ();

alexsmail 13.03.2013 09:16

@ shrini1000 идея состоит в том, чтобы использовать этот фрагмент там, где необходима информация, а не помещать его в библиотечную процедуру.

Thorbjørn Ravn Andersen 15.04.2013 12:54

@Devin Я вижу, что здесь также используется собственный API, например throwable. Итак, насколько быстро он по сравнению с другими методами, такими как StackTrace ..?

Kanagavelu Sugumar 06.11.2013 17:35

Будет ли это создавать анонимный внутренний класс во время компиляции, даже если вы поместите этот код в блок catch?

Adam Jensen 19.08.2014 05:28

@AdamJensen, класс будет создан / скомпилирован во время компиляции, но экземпляры будут созданы только в том случае, если они будут выполнены в блоке catch.

Brett Okken 17.02.2015 05:19

Спасибо за советы! Вместо создания нового объекта просто используйте this.getClass (). GetEnclosingMethod (). GetName ();

Lilo 27.03.2015 16:36

А как насчет статических методов? "нестатическая переменная, на которую нельзя ссылаться из статического контекста"

cloudsurfin 11.04.2015 02:24

можно ли получить значения параметров при вызове .getEnclosingMethod().getParameters()?

wutzebaer 14.08.2016 01:30

@wutzebaer Нет. Объект Method касается только метода и не имеет информации о текущем или каком-либо его вызове.

Adowrath 23.02.2017 18:43

@ Лило неверно. getEnclosingMethod получает имя метода, в котором определен класс. this.getClass() вам совсем не поможет. @wutzebaer, зачем тебе это вообще нужно? У вас уже есть к ним доступ.

Hazel Troost 20.09.2017 19:25

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

Это все еще тонко зависит от поставщика. JVM не требуется для доставки надежных данных для этого кода.

Thorbjørn Ravn Andersen 15.04.2013 12:56

Согласно спецификации JVM, JVM не требуется для обеспечения трассировки полного стека (оптимизация, встраивание и все такое), и вы уже обнаружили, что ваша эвристика изменилась между Oracle Java 5 и Oracle Java 6. Нет никаких гарантий, что любая другая JVM будет вести себя так, как вы ожидаете в своем коде, поэтому вы тонко полагаетесь на поведение конкретного поставщика. Что совершенно нормально, если вы об этом знаете, но если, например, вам нужно развернуть на IBM JVM (что мы должны) или на экземпляре Zing, вам, возможно, придется пересмотреть свою эвристику.

Thorbjørn Ravn Andersen 16.04.2013 18:22

Это кажется наиболее надежным из всех представленных здесь вариантов, несмотря на зависимости.

Ian 04.03.2018 04:41

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

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

Это выводит на печать "getStackTrace" для меня - я использую Java 1.5.

Zack Macomber 06.02.2013 00:17

будьте осторожны с пустым массивом в соответствии с ответом Bombe и указанием javadoc. Некоторые JVM могут не заполнять массив stacktrace?

el-teedee 28.02.2018 17:29

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

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

Самый быстрый по производительности? Какие-нибудь микро-тесты, подтверждающие это утверждение?

Ibrahim Arief 24.08.2012 13:27

+1. Используя простой временной цикл на 1.6, 1000000 итераций с использованием этого метода заняли 1219 мс, в то время как использование new Throwable().getStackTrace() заняло 5614 мс.

ach 25.01.2013 21:14

m.setAccessible (правда); должен быть окружен AccessController.doPrivileged. Что-то, что нужно учитывать, я бы сказал, не жесткое правило

avanderw 23.01.2014 13:47

Протестировано в 2016 году и по-прежнему остается самым быстрым. Как и @ach, я использовал 1 млн итераций. 1.7_79: 1,6 с против 15,2 с 1,8_74: 1,8 с против 16,0 с. FWIW мой тестовый массив ste array length == 23, но этот метод остается быстрым независимо от глубины стека.

Ryan 30.06.2016 20:54

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

В сочетании с ответом @mklemenz это очень быстрый и чистый способ доступа к информации о стеке.

Octavia Togami 27.07.2013 05:11
 public class SomeClass {
   public void foo(){
      class Local {};
      String name = Local.class.getEnclosingMethod().getName();
   }
 }

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

Local.class.getEnclosingMethod () имеет значение null. jdk1.6.0_31, играть в 1.2.5

eigil 29.11.2013 19:33

@eigil, это интересно, но без дополнительной информации трудно сказать, что пошло "не так" или когда нам следует ожидать null.

Maarten Bodewes 15.04.2014 14:07

Это тот же трюк, что и этот ответ. Его преимущество в том, что он не создает поддельный экземпляр объекта, а недостаток в том, что он требует объявления класса, которое не может быть встроено в оператор (т.е. обычно требуется дополнительная строка кода).

Maarten Bodewes 15.04.2014 14:25

@eigil вы определили класс внутри класса (пример SomeClass) или внутри метода (пример foo)? Я обнаружил, что определение подкласса без упаковки в метод или конструктор приведет к тому, что getEnclosingMethod () вернет значение null.

D.N. 10.03.2015 20:22

Совершенно уверен, что я сделал именно то, что описано в этом ответе. Я думаю, что с playframework что-то странно. Протестировано на "нормальной" java без проблем.

eigil 26.03.2015 14:24

Это будет работать, только если метод статический.

Felipe Mosso 27.01.2021 00:48
String methodName =Thread.currentThread().getStackTrace()[1].getMethodName();
System.out.println("methodName = " + methodName);

См. Ответы mvanle virgo47 выше и комментарий thorbjorn-ravn-andersen. Повторяющийся, неточный и ненадежный код.

alexsmail 07.07.2013 17:25

@ShivaKomuravelly Да, но, похоже, ни в какой ситуации, так что и от меня -1 тоже.

Maarten Bodewes 15.04.2014 14:12
public static String getCurrentMethodName() {
        return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName();
    }

Да, безусловно, лучший ... превратите его в метод и получите третий ([2]) фрейм (или как он там называется) в трассировке.

mike rodent 23.10.2016 13:28

Что плохого в таком подходе:

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

@Saksham, мне кажется, это была попытка ответить на вопрос. Не лучшая попытка, но все же попытка.

ivarni 25.08.2014 09:48

@ivarni "плохая попытка"? что с этим не так? Вам знаком "принцип поцелуя"?

johnny 25.08.2014 10:31

@Saksham, это было риторически.

johnny 25.08.2014 10:33

@johnny В кодовой базе, которую я сейчас вижу, 271 класс. Даже с (низкой оценкой) 5 методов на класс, что составляет более 1300 методов. И это даже не большая кодовая база. Вы не видите проблемы с расширением вашего подхода? Я вполне счастлив согласиться с тем, что не согласен, но именно поэтому я сказал, что это плохая попытка. Это приводит к огромным накладным расходам в любой нетривиальной кодовой базе.

ivarni 25.08.2014 10:37

@ivarni, разве вам не нужно включать вызов метода в каждый метод (как предложено выше), чтобы выполнять ту же самую и МЕНЬШЕ надежную функцию?

johnny 25.08.2014 10:42

@johnny Нет, если вы используете аспект.

ivarni 25.08.2014 10:45

На мой взгляд, основная проблема в том, что я буду повторяться. Это вредит ремонтопригодности. Теперь я не являюсь поклонником уловок с трассировкой стека, локального класса или исключений, поскольку они негативно влияют на производительность и иногда ненадежны для чего-то очень хорошего компилятора знает во время компиляции. Я лично пришел сюда в поисках чего-то вроде __func__, но подозреваю, что мы в конечном итоге остановимся на подходе Johnnys, поскольку он кажется наименее плохим.

Just another metaprogrammer 25.08.2014 18:00

@FuleSnabel "вредит ремонтопригодности"? вы говорите об одной строке кода для каждого метода, он всегда вызывается, вы всегда знаете, где находитесь, и вам не нужны сторонние утилиты. Я не понимаю, почему люди думают, что это главная проблема. он также отлично подходит для проверки параметров.

johnny 25.08.2014 19:22

@johnny Думаю, я видел слишком много случаев, когда имя метода не соответствует строке, которая отправила меня в неправильном направлении при отладке. Но в Java я по-прежнему считаю ваше предложение лучшим, другие альтернативы «стоят» слишком дорого.

Just another metaprogrammer 26.08.2014 14:59

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

Из Throwable.getStackTrace () (как минимум, начиная с Java 5):

The zeroth element of the array (assuming the array's length is non-zero) represents the top of the stack, which is the last method invocation in the sequence. Typically, this is the point at which this throwable was created and thrown.

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

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

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

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

Или же:

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

для статических методов используйте: <Class> .class.getEnclosingMethod (). getName ()

jellobird 31.05.2017 13:21

будьте осторожны с пустым массивом в соответствии с ответом Bombe и указанием javadoc. Некоторые JVM могут не заполнять массив stacktrace?

el-teedee 28.02.2018 17:29

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

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

Это работает на моем MacBook, а также на моем телефоне Android.

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

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

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

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

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

В недавнем тестировании на Android мне показалось, что лучше использовать getStackTrace()[0], чем getStackTrace()[1]. YMMV.

mbm29414 21.03.2016 18:23

вверх для android - это Thread.currentThread().getStackTrace()[2]

Ninja 17.10.2017 14:05

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
    }
}
final StackTraceElement e = Thread.currentThread().getStackTrace()[2]; работает; e.getClassName(); возвращает полное имя класса, а e.getMethodName() возвращает имя метона.
Marks 26.11.2015 15:05
getStackTrace()[2] неверен, это должен быть getStackTrace()[3], потому что: [0] dalvik.system.VMStack.getThreadStackTrace [1] java.lang.Thread.getStackTrace [2] Utils.getCurrentClassAndMethodNames [3] Функция a (), вызывающая этот
PhilLab 13.07.2017 19:59

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

Пожалуйста, отредактируйте с дополнительной информацией. Ответы только на код и "попробуйте это" не приветствуются, потому что они не содержат доступного для поиска контента и не объясняют, почему кто-то должен "попробовать это".

abarisone 27.09.2016 17:31

Хотя этот код может помочь решить проблему, он не объясняет Зачем и / или как, он отвечает на вопрос. Предоставление этого дополнительного контекста значительно улучшило бы его долгосрочную образовательную ценность. Пожалуйста, редактировать свой ответ, чтобы добавить объяснение, в том числе, какие ограничения и предположения применяются.

Toby Speight 28.09.2016 11:27

Только для Java 7+, но краткий способ получить имя метода. Тем не менее, остается соображение производительности такого вызова.

Benj 11.10.2016 15:29
getEnclosingMethod() бросает мне NullPointerException в Java 7.
Markus L 07.04.2017 12:47

Java.lang.Class.getEnclosingMethod () возвращает объект Method, представляющий непосредственно включающий метод базового класса, если этот объект Class представляет локальный или анонимный класс внутри метода, иначе возвращает null.

stove 25.04.2018 10:21

Каков след такого звонка?

Benj 27.07.2018 16:35

Это неверный ответ. lookup().lookupClass() возвращает класс текущего метода, а getEnclosingMethod() возвращает метод, в котором объявлен текущий класс, если текущий класс является локальным классом. См. ideone.com/jfN5GW. Другими словами, для данного void foo() { class Local { void bar() { System.out.println(lookup().lookupClass().getEnclosingMethod‌​()); } } new Local().bar(); } печатается метод foo() (потому что это включающий метод Local), но для этого вопроса нужен метод bar() (потому что это метод, который «выполняется в данный момент»).

Radiodef 14.09.2018 18:57

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

На всякий случай, если метод, имя которого вы хотите узнать, является тестовым методом junit, вы можете использовать правило junit TestName: https://stackoverflow.com/a/1426730/3076107

@AndreiKonstantinov Я не думаю, что это только ссылка. Даже если вы удалите ссылку, все равно останется как минимум информация некоторый.

EJoshuaS - Reinstate Monica 28.05.2019 02:22

Это можно сделать с помощью 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 для получения дополнительной информации.

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

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

Большинство ответов здесь кажется неправильным.

    public static String getCurrentMethod() {
            return getCurrentMethod(1);
    }
    public static String getCurrentMethod(int skip) {
            return Thread.currentThread().getStackTrace()[1 + 1 + skip].getMethodName();
    }

Пример:

    public static void main(String[] args) {
            aaa();
    }

    public static void aaa() {
            System.out.println("aaa  -> "  + getCurrentMethod( ) );
            System.out.println("aaa  -> "  + getCurrentMethod(0) );
            System.out.println("main -> "  + getCurrentMethod(1) );
    }

Выходы:

aaa  -> aaa
aaa  -> aaa
main -> main

Спасибо за полезный ответ.

AmerllicA 05.05.2020 22:08

Не могли бы вы пояснить, почему большинство ответов кажется вам неправильным? Есть много ответов, и я не настолько хорошо разбираюсь в Java, чтобы прочитать их все и понять, в чем разница между ними и вашим ответом. :(

Xobotun 06.05.2020 17:35

@mmm Извините, но я категорически не согласен. Я приехал сюда, чтобы учиться, и многие другие, как мне кажется, тоже. Я просто не могу понять, почему, по вашему мнению, я не заслуживаю более подробной информации по этому вопросу. Я хочу делать меньше ошибок в своем коде и предупреждать других, а не придерживаться какого-то карго-культа. Вы могли бы хотя бы уточнить, для какой версии Java этот код должен быть правильным. :( В ответе ниже говорится, что между 1.5 и 1.6 было изменение в stacktrace. Может быть, вы имеете в виду, что в грядущей Java 14 есть что-то подобное. Или это может быть у другого поставщика. Извините, если я неправильно истолковал ваш ответ как грубый один.

Xobotun 10.05.2020 19:18

Другие вопросы по теме