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

470

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

Омар Кохеджи
источник

Ответы:

177

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

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

Бомбы
источник
7
Верна ли эта та же ошибка для трассировки стека в исключениях?
Нейт Парсонс
8
Да, это так. Документация для Throwable . [GetStackTrace ()] ( download.oracle.com/javase/1.5.0/docs/api/java/lang/… содержит точно такой же абзац.
Bombe
4
В основе лежит то, что JVM не обязана обеспечивать возможность трассировки стека, но много работы ушло на то, чтобы сделать HotSpot очень надежным. Однако вам нужно знать, если вы хотите, чтобы ваш код не зависел от поведения конкретной JVM.
Торбьерн Равн Андерсен
Приведенная ниже версия Alexsmail не создает трассировку стека и дает вам доступ к реальному объекту метода, а не только к имени (так что вы также можете узнать тип возвращаемого значения). Я не отмечал на скамейке, но я подозреваю, что его метод намного быстрее, так как трассировка стека, как правило, дорогая.
Гас
Ответ Девина, кажется, дает гораздо более краткий ответ на этот вопрос.
восходящий поток
310

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

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

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

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

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

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

Девин
источник
9
Это не даст вам метод выполнения в настоящее время. Это даст вам тот метод, в котором определен анонимный / локальный класс. - docs.oracle.com/javase/6/docs/api/java/lang/…
shrini1000
7
класс Local {}; String name = Local.class.getEnclosingMethod (). GetName ();
alexsmail
21
@ shrini1000 Идея состоит в том, чтобы использовать этот фрагмент там, где нужна информация, а не помещать ее в рутину библиотеки.
Торбьерн Равн Андерсен
4
Спасибо за советы! Вместо создания нового объекта просто используйте this.getClass (). GetEnclosingMethod (). GetName ();
Лило
3
@ Лило неверно. getEnclosingMethodполучает имя метода, в котором определен класс. this.getClass()не поможет тебе вообще. @wutzebaer зачем тебе это вообще нужно? У вас уже есть доступ к ним.
Хейзел Трост
134

Январь 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 года:

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

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

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

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

VonC
источник
2
Это говорит только «главный» для меня. : - /
Проф. Фалькен нарушил контракт
@Amigable: вы пытались напечатать StackTraceElementмассив all для отладки и посмотреть, действительно ли 'main' является правильным методом?
VonC
7
Я использую JRE 6 и дает мне неправильное имя метода. Это работает, если я пишу ste[2 + depth].getMethodName(). 0 есть getStackTrace(), 1 есть getMethodName(int depth)и 2 вызывает метод. Смотрите также ответ @ virgo47 .
голубоватое
2
@ синий: хорошая мысль. Я включил ваш комментарий и ссылку на ответ virgo47 в мой.
VonC
@VonC Является ли эта реализация действительно правильной? глубина здесь должна быть ste.length + 1 для того, чтобы дать текущий метод. Разве это не должно быть ste [глубина + 1], если мы хотим, чтобы глубина = 0?
ммм
85

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

virgo47
источник
1
Это все еще слегка зависит от поставщика. JVM не обязана предоставлять надежные данные для этого кода.
Торбьерн Равн Андерсен
6
Согласно спецификации JVM, JVM не обязана предоставлять полные трассировки стека (оптимизация, встраивание и все такое), и вы уже обнаружили, что ваша эвристика изменилась между Oracle Java 5 и Oracle Java 6. Ничто не гарантирует, что любая другая JVM будет ведите себя так, как вы ожидаете в своем коде, поэтому вы тонко полагаетесь на поведение конкретного поставщика. Это прекрасно, если вы знаете об этом, но если - например, вам нужно развернуть на IBM JVM (что мы должны) или на экземпляре Zing, вам, возможно, придется пересмотреть свою эвристику.
Турбьёрн Равн Андерсен
1
Это кажется наиболее надежным из всех представленных здесь вариантов, несмотря на зависимости.
Ян
46
 public class SomeClass {
   public void foo(){
      class Local {};
      String name = Local.class.getEnclosingMethod().getName();
   }
 }

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

alexsmail
источник
5
Local.class.getEnclosingMethod () был нулевым. jdk1.6.0_31, игра 1.2.5
eigil
@eigil, это интересно, но без дополнительной информации трудно сказать, что пошло «не так» или когда нам следовало ожидатьnull
Maarten Bodewes
Это тот же трюк, что и этот ответ . У него есть то преимущество, что он не создает ложный экземпляр объекта, у него есть тот недостаток, что он требует объявления класса, которое не может быть встроено в оператор (т. Е. Обычно требуется дополнительная строка кода).
Maarten Bodewes
@eigil вы определили класс внутри класса (пример SomeClass) или внутри метода (пример foo)? Я обнаружил, что определение подкласса без использования метода или конструктора приведет к тому, что getEnclosingMethod () вернет значение null.
DN
Уверен, я сделал именно так, как описано в этом ответе. Я думаю, что это что-то странное с игровой структурой. Протестировано в «нормальной» Java без каких-либо проблем.
Eigil
36

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

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

Или:

Thread.currentThread().getStackTrace()[1].getMethodName()
Чарли Селигман
источник
1
для статических методов используйте: <Class> .class.getEnclosingMethod (). getName ()
jellobird
быть осторожным с пустым массивом в соответствии с ответом Bombe и указанием Javadoc. Некоторые JVM могут не заполнять массив трассировки стека?
Эль-Тиди
34

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

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


источник
3
Быстрее, как по производительности? Какой-нибудь микро-бенчмарк для поддержки претензии?
Ибрагим Краткий обзор
10
+1. При использовании простого синхронизированного цикла на 1.6, 1 000 000 итераций с использованием этого метода заняли 1219 мс, а при использовании - new Throwable().getStackTrace()5614 мс.
ACH
1
m.setAccessible (истина); должен быть окружен AccessController.doPrivileged. Что-то, чтобы рассмотреть, не жесткое правило, я бы сказал
avanderw
6
Протестировано в 2016 году и продолжает оставаться самым быстрым. Как @ach, я использовал 1M итераций. 1,7_79: 1,6 с против 15,2 с 1,8_74: 1,8 с против 16,0 с. Впрочем, длина моего эталонного массива ste == 23, но этот метод остается быстрым независимо от глубины стека.
Райан
25

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

    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
Для меня это выводит "getStackTrace" - я использую Java 1.5
Зак Макомбер
быть осторожным с пустым массивом в соответствии с ответом Bombe и указанием Javadoc. Некоторые JVM могут не заполнять массив трассировки стека?
Эль-Тиди
16
public static String getCurrentMethodName() {
        return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName();
    }
сойка
источник
Да, безусловно, лучший ... превратить его в метод и получить третий ([2]) кадр (или как он там называется) в трассировке.
Майк Грызун
14

Это расширение ответа virgo47 (см. Выше).

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

/* Utility class: Getting the name of the current executing method 
 * /programming/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. /programming/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 + ")";
    }
}
mvanle
источник
3
Это в сочетании с ответом @ mklemenz является очень быстрым и чистым способом доступа к информации стека.
Октавия Тогами
12

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

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
на андроид этоThread.currentThread().getStackTrace()[2]
ниндзя
11

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

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

Radiodef
источник
5

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

Из Throwable.getStackTrace () (это было так же, как минимум с Java 5):

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

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

System.out.printf("Class %s.%s\n", getClass().getName(), new Exception("is not thrown").getStackTrace()[0].getMethodName());
Jool
источник
4
String methodName =Thread.currentThread().getStackTrace()[1].getMethodName();
System.out.println("methodName = " + methodName);
RAN
источник
1
См. Ответы mvanle virgo47 выше и комментарий торбьерна-равна-андерсена. Повторение, неточный и ненадежный код.
alexsmail
@ShivaKomuravelly Да, но не в любой ситуации, кажется, так что -1 от меня тоже.
Maarten Bodewes
3

У меня есть решение с помощью этого (в 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())}));
    }
}
Касим Рангвала
источник
3

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

Джеймс Сельвакумар
источник
2

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

Egl
источник
1
@AndreiKonstantinov Я не думаю, что это только для ссылок. Даже если вы удалите ссылку, есть еще какая-то информация для продолжения.
EJoshuaS - Восстановить Монику
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
Не могли бы вы уточнить, почему большинство ответов кажется вам неправильным? Есть много ответов, и я не очень разбираюсь в Java, чтобы прочитать их все и понять, в чем разница между ними и вашим ответом. :(
Xobotun
@mmm Извините, но я категорически не согласен. Я прихожу сюда, чтобы учиться, и, как я полагаю, делают и многие другие. Я просто не могу понять, почему вы думаете, что я не заслуживаю знать больше на эту тему. Я хочу делать меньше ошибок в своем коде и предупреждать других, чтобы они не следовали за каким-то культом. Вы могли бы по крайней мере уточнить, в какой версии Java этот код должен быть корректным. :( В ответе ниже говорится, что в трассировке стека произошли изменения между 1,5 и 1,6. Может быть, вы подразумеваете, что в следующей версии Java 14 что-то подобное, как я могу знать. Или другой поставщик может иметь. Извините, если я неправильно истолковал ваш ответ как грубый один
Xobotun
0

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

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);
}
Марко Сулла
источник
-2
MethodHandles.lookup().lookupClass().getEnclosingMethod().getName();
Даррен
источник
11
Пожалуйста, отредактируйте с дополнительной информацией. Ответы «только код» и «попробуй это» не приветствуются, потому что они не содержат контента для поиска и не объясняют, почему кто-то должен «попробовать это».
abarisone
1
Хотя этот код может помочь решить проблему, он не объясняет, почему и / или как он отвечает на вопрос. Предоставление этого дополнительного контекста значительно улучшило бы его долгосрочную образовательную ценность. Пожалуйста, измените свой ответ, чтобы добавить объяснение, в том числе, какие ограничения и предположения применяются.
Тоби Спейт
1
Только для Java 7+, но сжатый способ получить имя метода. Тем не менее, остаются соображения производительности такого вызова.
Бендж,
6
getEnclosingMethod()бросает NullPointerExceptionдля меня в Java 7.
Маркус Л
2
Java.lang.Class.getEnclosingMethod () возвращает объект Method, представляющий непосредственно включающий метод базового класса, если этот объект Class представляет локальный или анонимный класс внутри метода, в противном случае возвращает null.
печь
-5

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

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());
        }
    }
Джонни
источник
4
@Saksham, мне кажется, это была попытка ответить на вопрос. Не большая попытка, но попытка, тем не менее.
ivarni
@ivarni "не очень хорошая попытка"? что с этим не так? Вы знакомы с «принципом поцелуя»?
Джонни
@Saksham это было риторическим.
Джонни
5
@johnny В кодовой базе передо мной сейчас 271 класс. Даже с (низкой оценкой) og 5 методов на класс, это более 1300 методов. И это даже не большая кодовая база. Вы не видите проблемы с расширением вашего подхода? Я очень рад согласиться не согласиться, но именно поэтому я сказал, что это не очень хорошая попытка. Это вносит огромное количество накладных расходов в любую нетривиальную кодовую базу.
ivarni
1
@johnny Думаю, я видел слишком много случаев, когда имя метода не совпадает со строкой, которая при отладке отправила меня в неправильном направлении. Но в Java я все еще думаю, что ваше предложение является лучшим, другие альтернативы "стоят" слишком дорого.
Просто еще один метапрограммист