Uzyskiwanie nazwy aktualnie wykonywanej metody


Odpowiedzi:


177

Thread.currentThread().getStackTrace()zwykle zawiera metodę, z której ją wywołujesz, ale występują pułapki (patrz Javadoc ):

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


7
Czy ten sam pułapek dotyczy śladów stosu w wyjątkach?
Nate Parsons

8
Tak to jest. Dokumentacja dla Throwable . [GetStackTrace ()] ( download.oracle.com/javase/1.5.0/docs/api/java/lang/... zawiera dokładnie ten sam punkt.
Bombe

4
Podstawową rzeczą jest to, że JVM nie musi być w stanie zapewnić śledzenia stosu, ale wiele pracy włożono w uczynienie HotSpot bardzo niezawodnym. Musisz jednak wiedzieć, na wypadek, gdyby Twój kod nie polegał na zachowaniu określonej maszyny JVM.
Thorbjørn Ravn Andersen

Poniższa wersja Alexsmail nie tworzy śledzenia stosu i zapewnia dostęp do rzeczywistego obiektu metody, a nie tylko nazwy (dzięki czemu można również znaleźć typ zwrotu). Nie zaznaczyłem stanowiska, ale podejrzewam, że jego metoda jest również znacznie szybsza, ponieważ ślady na stosie bywają kosztowne.
Gus,

Odpowiedź Devina wydaje się dawać o wiele bardziej zwięzłą odpowiedź na to pytanie.
riseTide

310

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.). Spowoduje to utworzenie .classpliku dla każdej metody wdrażającej tę sztuczkę. Dodatkowo przy każdym wywołaniu tworzona jest instancja nieużywanego obiektu w czasie wykonywania. Może to być dopuszczalna sztuczka debugowania, ale wiąże się to ze znacznym nakładem pracy.

Zaletą tej sztuczki jest to, że getEncosingMethod()zwroty java.lang.reflect.Methodmożna wykorzystać do pobrania wszystkich innych informacji o metodzie, w tym adnotacji i nazw parametrów. Umożliwia to rozróżnienie konkretnych metod o tej samej nazwie (przeciążenie metody).

Zauważ, że zgodnie z JavaDoc getEnclosingMethod()tej sztuczki nie należy rzucać, SecurityExceptionponieważ klasy wewnętrzne powinny być ładowane przy użyciu tego samego modułu ładującego klasy. Nie ma więc potrzeby sprawdzania warunków dostępu, nawet jeśli obecny jest menedżer bezpieczeństwa.

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


9
To nie da ci aktualnie wykonywanej metody. To da ci metodę definiowania anonimowej / lokalnej klasy. - docs.oracle.com/javase/6/docs/api/java/lang/…
shrini1000

7
klasa lokalna {}; Nazwa ciągu = Local.class.getEnclosingMethod (). GetName ();
alexsmail

21
@ shrini1000 chodzi o użycie tego fragmentu kodu tam, gdzie potrzebne są informacje, a nie umieszczanie go w bibliotece.
Thorbjørn Ravn Andersen

4
Dzięki za wskazówki! Zamiast tworzyć nowy obiekt, wystarczy użyć this.getClass (). GetEnclosingMethod (). GetName ();
Lilo,

3
@Lilo niepoprawny. getEnclosingMethodpobiera nazwę metody, w której klasa jest zdefiniowana. this.getClass()w ogóle ci nie pomoże. @wutzebaer, dlaczego miałbyś to robić? Masz już do nich dostęp.
Hazel Troost,

134

Styczeń 2009:
Pełny kod będzie (do użycia z zastrzeżeniem @ 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
}

Więcej w tym pytaniu .

Aktualizacja z grudnia 2011 r .:

niebieskawy komentarze:

Używam środowiska JRE 6 i podaje mi niepoprawną nazwę metody.
Działa, jeśli piszęste[2 + depth].getMethodName().

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

virgo47 „s odpowiedź (upvoted) rzeczywiście oblicza indeks prawo do zastosowania w celu uzyskania z powrotem nazwę metody.


2
Mówi tylko „główne” dla mnie. : - /
Umowa prof. Falkena została naruszona

@Amigable: czy próbowałeś wydrukować całą StackTraceElementtablicę w celu debugowania i sprawdzić, czy 'main' jest rzeczywiście właściwą metodą?
VCC,

7
Używam środowiska JRE 6 i podaje mi niepoprawną nazwę metody. Działa, jeśli piszę ste[2 + depth].getMethodName(). 0 oznacza getStackTrace(), 1 oznacza, getMethodName(int depth)a 2 wywołuje metodę. Zobacz także odpowiedź @ virgo47 .
niebieskawy

2
@bluish: dobry punkt. Zamieściłem twój komentarz i odniesienie do odpowiedzi virgo47 w mojej.
VonC

@VonC Czy ta implementacja jest naprawdę poprawna? głębokość tutaj musi wynosić stal. długość + 1, aby podać bieżącą metodę. Czy nie powinno być ste [głębokość + 1], jeśli mamy pozwolić na głębokość = 0?
mmm

85

Użyliśmy tego kodu, aby ograniczyć potencjalną zmienność indeksu śledzenia stosu - teraz wystarczy wywołać metodę methodName

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ę, że mamy nadmiar inżynierii, ale mieliśmy pewną stałą liczbę dla JDK 1.5 i byliśmy nieco zaskoczeni, że zmieniło się, kiedy przeszliśmy na JDK 1.6. Teraz jest tak samo w Javie 6/7, ale nigdy nie wiadomo. Nie świadczy to o zmianach tego indeksu w czasie wykonywania - ale mam nadzieję, że HotSpot nie robi tak źle. :-)


1
Nadal jest to subtelnie zależne od dostawcy. JVM nie jest wymagana do dostarczania wiarygodnych danych dla tego kodu.
Thorbjørn Ravn Andersen

6
Zgodnie ze specyfikacją JVM JVM nie musi zapewniać pełnych danych śledzenia stosu (optymalizacja, wstawianie itp.), A już odkryłeś, że twoja heurystyka zmieniła się między Oracle Java 5 a Oracle Java 6. Nic nie gwarantuje, że jakakolwiek inna maszyna JVM zachowuj się zgodnie z oczekiwaniami w kodzie, więc subtelnie polegasz na zachowaniu konkretnego dostawcy. Co jest w porządku, o ile zdajesz sobie z tego sprawę, ale jeśli - na przykład - musisz wdrożyć na IBM JVM (co musimy) lub na instancji Zing, być może będziesz musiał ponownie odwiedzić swoją heurystykę.
Thorbjørn Ravn Andersen

1
Wydaje się, że jest to najbardziej niezawodna ze wszystkich przedstawionych tu opcji, niezależnie od zależności.
Ian

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

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


5
Local.class.getEnclosingMethod () był null. jdk1.6.0_31, zagraj 1.2.5
wigilię

@eigil to ciekawe, ale bez dodatkowych informacji trudno jest powiedzieć, co poszło „źle” lub kiedy należy się spodziewaćnull
Maarten Bodewes

To ta sama sztuczka, co ta odpowiedź . Ma tę zaletę, że nie tworzy fałszywej instancji obiektu, ma tę wadę, że wymaga deklaracji klasy, której nie można wstawić w instrukcji (tzn. Zwykle wymaga dodatkowej linii kodu).
Maarten Bodewes

@eigil czy zdefiniowałeś klasę w klasie (przykład SomeClass), czy w metodzie (przykład foo)? Odkryłem, że zdefiniowanie podklasy bez zawijania w metodzie - lub w konstruktorze - spowoduje, że getEnclosingMethod () zwróci null.
DN

Jestem całkiem pewien, że zrobiłem dokładnie tak, jak opisano w tej odpowiedzi. Myślę, że to coś dziwnego w Playframework. Testowane w „normalnej” Javie bez żadnego problemu.
wigilia

36

Obie te opcje działają dla mnie w Javie:

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

Lub:

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

1
do metod statycznych użyj: <Class> .class.getEnclosingMethod (). getName ()
jellobird

uważaj na pustą tablicę zgodnie z odpowiedzią Bombe i wskazaniem javadoc. Niektóre maszyny JVM mogą nie wypełniać tablicy stacktrace?
el-teedee

34

Najszybciej odkryłem, że:

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.


3
Najszybszy jak pod względem wydajności? Jakieś mikro-wzorce na poparcie roszczenia?
Ibrahim Arief

10
+1. Używając prostej pętli czasowej na 1.6, 1.000.000 iteracji tą metodą zajęło 1219 ms, podczas gdy użycie new Throwable().getStackTrace()zajęło 5614 ms.
ach

1
m.setAccessible (true); powinien być otoczony AccessController.doPrivileged. Coś do rozważenia, nie jest to trudna zasada, powiedziałbym
avanderw

6
Testowany w 2016 roku i nadal jest najszybszy. Podobnie jak @ach użyłem iteracji 1M. 1,7_79: 1,6 s vs 15,2 s 1,8_74: 1,8 s vs 16,0 s. FWIW długość mojego zestawu testów porównawczych == 23, ale ta metoda działa szybko, niezależnie od głębokości stosu.
Ryan

25

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

2
To drukuje dla mnie „getStackTrace” - używam Java 1.5
Zack Macomber

uważaj na pustą tablicę zgodnie z odpowiedzią Bombe i wskazaniem javadoc. Niektóre maszyny JVM mogą nie wypełniać tablicy stacktrace?
el-teedee

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

Tak, zdecydowanie najlepszy ... przekształć go w metodę i uzyskaj trzecią ([2]) ramkę (lub jakkolwiek to się nazywa) w śladzie.
Mike Gryzonie

14

Jest to rozszerzenie odpowiedzi virgo47 (powyżej).

Zapewnia niektóre metody statyczne, aby uzyskać bieżące i wywołujące nazwy klas / metod.

/* 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 + ")";
    }
}

3
W połączeniu z odpowiedzią @ mklemenz jest to bardzo szybki i czysty sposób na dostęp do informacji o stosie.
Octavia Togami,

12

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

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

Działa to na moim MacBooku, a także na telefonie z Androidem

Próbowałem także:

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

ale Android zwróci „getStackTrace”. Mogę to naprawić dla Androida

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

ale potem otrzymuję złą odpowiedź na moim MacBooku


W ostatnich testach na Androidzie lepiej było dla mnie używać getStackTrace()[0], niż getStackTrace()[1]. YMMV.
mbm29414,

dla Androida jestThread.currentThread().getStackTrace()[2]
Ninja

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

final StackTraceElement e = Thread.currentThread().getStackTrace()[2]; Pracuje; e.getClassName();zwraca pełną nazwę klasy i e.getMethodName()zwraca nazwę methon.
Znaki

1
getStackTrace()[2]jest źle, musi być tak, getStackTrace()[3]ponieważ: [0] dalvik.system.VMStack.getThreadStackTrace [1] java.lang.Thread.getStackTrace [2] Utils.getCurrentClassAndMethodNames [3] Funkcja a () wywołująca tę
funkcję

11

Można to zrobić za pomocą 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();
}

StackWalkerjest zaprojektowany tak, aby był leniwy, więc może być bardziej wydajny niż, powiedzmy, Thread.getStackTracektóry chętnie tworzy tablicę dla całego zestawu wywołań. Zobacz także JEP, aby uzyskać więcej informacji.


5

Alternatywną metodą jest utworzenie, ale nie zgłoszenie wyjątku, i użycie tego obiektu, z którego można pobrać dane śledzenia stosu, ponieważ metoda zamykająca zwykle ma indeks 0 - o ile JVM przechowuje te informacje, tak jak inni wspomniano powyżej. Nie jest to jednak najtańsza metoda.

Od Throwable.getStackTrace () (było tak samo od co najmniej Java 5):

Element zerowy tablicy (przy założeniu, że długość tablicy jest różna od zera) reprezentuje górę stosu, która jest ostatnim wywołaniem metody w sekwencji. Zazwyczaj jest to punkt, w którym ten rzucalny został stworzony i rzucony.

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

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

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

1
Zobacz odpowiedzi mvanle virgo47 powyżej i komentarz thorbjorn-ravn-andersen. Powtarzalny, nieprecyzyjny i niewiarygodny kod.
alexsmail

@ShivaKomuravelly Tak, ale nie w żadnej sytuacji, więc -1 ode mnie.
Maarten Bodewes

3

Mam rozwiązanie korzystające z tego (w Androidzie)

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

Nie wiem, jaki jest zamiar uzyskania nazwy obecnie wykonywanej metody, ale jeśli jest to tylko w celu debugowania, struktury rejestrowania takie jak „logback” mogą tutaj 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 obniżyć wydajność.



1

Większość odpowiedzi tutaj wydaje się błędna.

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

Przykład:

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

Wyjścia:

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

Dziękuję za przydatną odpowiedź.
AmerllicA

Czy możesz wyjaśnić, dlaczego większość odpowiedzi wydaje się dla Ciebie niewłaściwa? Istnieje wiele odpowiedzi i nie jestem zbyt dobrze zaznajomiony z Javą, aby przeczytać je wszystkie i zrozumieć, jaka jest różnica między nimi a twoją odpowiedzią. :(
Xobotun

@mmm Przepraszam, ale zdecydowanie się nie zgadzam. Wierzę, że przychodzę tutaj, aby się uczyć, podobnie jak wielu innych. Po prostu nie rozumiem, dlaczego według ciebie nie zasługuję na więcej informacji na ten temat. Chcę popełniać mniej błędów w moim kodzie i ostrzegać innych, nie podążając za kultem ładunków. Mogłeś przynajmniej wyjaśnić, w jakiej wersji Java ten kod powinien być poprawny. :( Poniższa odpowiedź mówi, że nastąpiła zmiana w ustawieniach śledzenia między 1.5 a 1.6. Być może sugerujesz, że coś takiego ma się w nadchodzącej Javie 14, skąd mam wiedzieć. Albo może inny sprzedawca. Przepraszam, jeśli źle zinterpretowałem twoją odpowiedź jeden
Xobotun

0

Przepisałem trochę odpowiedź maklemenz :

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
Edytuj, podając więcej informacji. Odradzane są tylko kody i odpowiedzi „wypróbuj to”, ponieważ nie zawierają one treści, które można przeszukiwać, i nie wyjaśniają, dlaczego ktoś powinien „wypróbować to”.
abarisone

1
Chociaż ten kod może pomóc w rozwiązaniu problemu, nie wyjaśnia, dlaczego i / lub jak odpowiada na pytanie. Zapewnienie tego dodatkowego kontekstu znacznie poprawiłoby jego długoterminową wartość edukacyjną. Proszę edytować swoje odpowiedzi, aby dodać wyjaśnienie, w tym, co stosuje się ograniczenia i założenia.
Toby Speight,

1
Tylko dla Java 7+, ale zwięzły sposób na uzyskanie nazwy metody. Pozostaje jednak kwestia wydajności takiego połączenia.
Benj,

6
getEnclosingMethod()rzuca NullPointerExceptiondla mnie w Javie 7.
Markus L

2
Metoda java.lang.Class.getEnclosingMethod () zwraca obiekt Method reprezentujący bezpośrednio obejmującą metodę klasy bazowej, jeśli ten obiekt Class reprezentuje klasę lokalną lub anonimową w ramach metody, w przeciwnym razie zwraca null.
piec

-5

Co jest złego w tym podejściu:

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 temat używania System.out.println(...), zawsze możesz i powinieneś stworzyć jakąś metodę, aby dane wyjściowe mogły zostać przekierowane, 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());
        }
    }

4
@Saksham wygląda mi to na próbę odpowiedzi na pytanie. Nie jest to świetna próba, ale próba.
ivarni

@ivarni „nie jest to dobra próba”? co jest z tym nie tak? znasz „zasadę pocałunku”?
Johnny

@Saksham to było retoryczne.
Johnny

5
@johnny W bazie kodu, którą mam teraz przed sobą, jest 271 klas. Nawet przy (niskiej ocenie) og 5 metod na klasę, co daje ponad 1300 metod. I to nie jest nawet duża baza kodów. Nie widzisz problemu ze zwiększeniem swojego podejścia? Z przyjemnością zgadzam się nie zgadzać, ale dlatego powiedziałem, że to nie jest dobra próba. Wprowadza ogromne koszty ogólne w każdej nietrywialnej bazie kodu.
ivarni

1
@ johnny Chyba widziałem zbyt wiele przypadków, w których nazwa metody nie zgadza się z ciągiem, który wysłał mnie w złym kierunku podczas debugowania. Ale w Javie nadal uważam, że twoja sugestia jest najlepsza, inne alternatywy „kosztują” za dużo.
Kolejny metaprogramator
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.