Uzyskanie nazwy aktualnie wykonywanej metody

Czy istnieje sposób na uzyskanie nazwy aktualnie wykonywanej metody w Javie?

Author: Kedar Mhaswade, 2009-01-14

20 answers

Thread.currentThread().getStackTrace() zazwyczaj zawiera metodę, z której ją wywołujesz, ale istnieją pułapki (Zobacz Javadoc):

Niektóre maszyny wirtualne mogą w pewnych okolicznościach pominąć jedną lub więcej ramek stosu ze śladu stosu. W skrajnym przypadku maszyna wirtualna, która nie posiada informacji o śledzeniu stosu dotyczących tego wątku, może zwrócić tablicę o zerowej długości z tej metody.

 153
Author: Bombe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-28 12:51:10

Technicznie to zadziała...

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

Jednak nowa anonimowa Klasa wewnętrzna zostanie utworzona podczas kompilacji (np. YourClass$1.class). Utworzy to plik .class dla każdej metody, która zastosuje tę sztuczkę. Dodatkowo przy każdym wywołaniu w czasie wykonywania jest tworzona nieużywana instancja obiektu. Więc może to być akceptowalna sztuczka debugowania, ale wiąże się to ze znacznymi kosztami.

Zaletą tej sztuczki jest to, że getEncosingMethod() zwraca java.lang.reflect.Method, które można wykorzystać do odzyskania wszystkie inne informacje dotyczące metody, w tym adnotacje i nazwy parametrów. Umożliwia to rozróżnienie konkretnych metod o tej samej nazwie (metoda overload).

Zauważ, że zgodnie z JavaDoc {[5] } ta sztuczka nie powinna rzucać SecurityException, ponieważ wewnętrzne klasy powinny być ładowane za pomocą tego samego class loader. Nie ma więc potrzeby sprawdzania warunków dostępu, nawet jeśli obecny jest menedżer zabezpieczeń.

Wymagane jest użycie getEnclosingConstructor() dla konstruktorów. Podczas bloków poza (nazwanymi) metodami, getEnclosingMethod() zwraca null.

 267
Author: Devin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-15 10:30:13

Styczeń 2009:
Pełny kod byłby (do użycia z zastrzeżeniem @Bombe w umyśle):

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

Więcej w to pytanie.

Aktualizacja Grudzień 2011:

Bluish komentarze:

Używam JRE 6 i podaję niepoprawną nazwę metody.
Działa jeśli napiszę ste[2 + depth].getMethodName().

  • 0 jest getStackTrace(),
  • 1 jest getMethodName(int depth) i
  • 2 jest metodą wywoływania.

Virgo47 'S answer (upvoted) faktycznie oblicza odpowiedni Indeks do zastosowania, aby odzyskać nazwę metody.

 128
Author: VonC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:28

Użyliśmy tego kodu, aby złagodzić potencjalną zmienność w indeksie śledzenia stosu - teraz wystarczy wywołać 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();
    }
}

Wydaje się zbyt rozbudowany, ale mieliśmy jakiś stały numer dla JDK 1.5 i byliśmy trochę zaskoczeni, że zmienił się, gdy przenieśliśmy się na JDK 1.6. Teraz jest tak samo w Javie 6/7, ale nigdy nie wiadomo. Nie jest to dowód na zmiany w tym indeksie podczas wykonywania - ale mam nadzieję, że HotSpot nie robi tak źle. :-)

 80
Author: virgo47,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-21 16:13:03
 public class SomeClass {
   public void foo(){
      class Local {};
      String name = Local.class.getEnclosingMethod().getName();
   }
 }

Nazwa będzie miała wartość foo.

 41
Author: alexsmail,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-13 05:21:06

Najszybszy sposób jaki znalazłem to:

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

Uzyskuje bezpośredni dostęp do natywnej metody getStackTraceElement(int depth). I przechowuje dostępną metodę w zmiennej statycznej.

 28
Author: maklemenz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-30 17:40:37

Użyj następującego kodu:

    StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
    StackTraceElement e = stacktrace[1];//coz 0th will be getStackTrace so 1st
    String methodName = e.getMethodName();
    System.out.println(methodName);
 23
Author: Sumit Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-05 04:52:28

Obie te opcje działają dla mnie z Javą:

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

Lub:

Thread.currentThread().getStackTrace()[1].getMethodName()
 22
Author: Charlie Seligman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-01 10:21:59
public static String getCurrentMethodName() {
        return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName();
    }
 14
Author: Jay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-13 10:07:55

Jest to rozszerzenie na odpowiedź virgo47 (powyżej).

Dostarcza statycznych metod, aby uzyskać bieżące i wywołujące nazwy klas / metod.

/* 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 + ")";
    }
}
 13
Author: mvanle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:56

Aby uzyskać nazwę metody, która wywołała bieżącą metodę, możesz użyć:

new Exception("is not thrown").getStackTrace()[1].getMethodName()
To działa zarówno na moim MacBooku, jak i na moim telefonie z Androidem]}

Ja też próbowałem:

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

Ale Android zwróci " getStackTrace" Mogę to naprawić dla Androida za pomocą

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

Ale potem dostaję złą odpowiedź na moim MacBooku

 11
Author: Friso van der Made,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-22 10:53:08

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
    }
}
 9
Author: Maxple,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-03 10:36:09

Alternatywną metodą jest tworzenie, ale nie rzucanie, wyjątku i używanie tego obiektu, z którego pobiera się dane śledzenia stosu, ponieważ metoda zamykająca będzie typowo BYĆ w indeksie 0 - tak długo, jak JVM przechowuje te informacje, jak inni wspomniali powyżej. Nie jest to jednak najtańsza metoda.

From Throwable.getStackTrace () (to samo przynajmniej od Javy 5):

Element zerowy tablicy (zakładając, że długość tablicy jest niezerowa) przedstawia wierzchołek stosu, który jest ostatnim wywołaniem metody w sekwencji. typowo, to jest punkt, w którym ten throwable został stworzony i wyrzucony.

Poniższy fragment zakłada, że klasa jest niestatyczna (z powodu getClass ()), ale jest to Pomijanie.

System.out.printf("Class %s.%s\n", getClass().getName(), new Exception("is not thrown").getStackTrace()[0].getMethodName());
 4
Author: Jool,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-15 12:17:41
String methodName =Thread.currentThread().getStackTrace()[1].getMethodName();
System.out.println("methodName = " + methodName);
 3
Author: ran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-03 12:06:44

Nie wiem, jaki jest cel uzyskania nazwy aktualnie wykonywanej metody, ale jeśli jest to tylko w celu debugowania, to logowanie frameworków takich jak "logback" może tu pomóc. Na przykład, w logback, wszystko, co musisz zrobić, to użyć wzorca "% M " w konfiguracji logowania . Należy jednak zachować ostrożność, ponieważ może to pogorszyć wydajność.

 3
Author: James Selvakumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:41

I ' ve got solution using this (in 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())}));
    }
}
 2
Author: Kasim Rangwala,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-03 07:35:29

Na wypadek, gdyby nazwa metody, którą chcesz znać, była metodą testową junit, możesz użyć reguły junit TestName: https://stackoverflow.com/a/1426730/3076107

 2
Author: Egl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-20 14:08:44
MethodHandles.lookup().lookupClass().getEnclosingMethod().getName();
 1
Author: Darren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-27 10:20:09

Można to zrobić za pomocą StackWalker od 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 jest zaprojektowany, aby być leniwym, więc prawdopodobnie będzie bardziej wydajny niż, powiedzmy, Thread.getStackTrace, który chętnie tworzy tablicę dla całego callstacka. Zobacz także JEP, aby uzyskać więcej informacji.

 0
Author: Radiodef,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-14 15:45:13

Co jest nie tak z tym podejściem:

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

I zanim ludzie oszaleją na punkcie używania System.out.println(...) zawsze możesz i powinieneś stworzyć jakąś metodę, aby można było przekierować wyjście, np:

    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());
        }
    }
 -5
Author: johnny,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-21 12:59:25