Abrufen des Namens der aktuell ausgeführten Methode

470

Gibt es eine Möglichkeit, den Namen der aktuell ausgeführten Methode in Java abzurufen?

Omar Kooheji
quelle

Antworten:

177

Thread.currentThread().getStackTrace()enthält normalerweise die Methode, von der Sie es aufrufen, aber es gibt Fallstricke (siehe Javadoc ):

Einige virtuelle Maschinen können unter bestimmten Umständen einen oder mehrere Stapelrahmen aus der Stapelverfolgung weglassen. Im Extremfall darf eine virtuelle Maschine, die keine Stapelverfolgungsinformationen zu diesem Thread enthält, ein Array mit der Länge Null von dieser Methode zurückgeben.

Bombe
quelle
7
Gilt das auch für Stack-Traces in Ausnahmen?
Nate Parsons
8
Ja, so ist es. Die Dokumentation für Throwable . [GetStackTrace ()] ( download.oracle.com/javase/1.5.0/docs/api/java/lang/… enthält genau den gleichen Absatz.
Bombe
4
Die zugrunde liegende Sache ist , dass die JVM ist nicht erforderlich einen Stacktrace schaffen zu können, dass aber eine Menge Arbeit in der Herstellung HotSpot sehr zuverlässig gegangen. Sie müssen jedoch wissen, ob Ihr Code nicht vom Verhalten einer bestimmten JVM abhängt.
Thorbjørn Ravn Andersen
Die folgende Version von Alexsmail erstellt keine Stapelverfolgung und gibt Ihnen Zugriff auf das eigentliche Methodenobjekt, nicht nur auf den Namen (damit Sie auch den Rückgabetyp herausfinden können). Ich habe kein Benchmarking durchgeführt, aber ich vermute, dass seine Methode auch viel schneller ist, da Stapelspuren in der Regel teuer sind.
Gus
Devins Antwort scheint eine viel prägnantere Antwort auf diese Frage zu geben.
RisingTide
310

Technisch wird das funktionieren ...

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

Während der Kompilierungszeit wird jedoch eine neue anonyme innere Klasse erstellt (z YourClass$1.class. B. ). Das schafft also eine.class für jede Methode, die diesen Trick ausführt Datei erstellt. Zusätzlich wird bei jedem Aufruf zur Laufzeit eine ansonsten nicht verwendete Objektinstanz erstellt. Dies mag also ein akzeptabler Debug-Trick sein, bringt jedoch einen erheblichen Overhead mit sich.

Ein Vorteil dieses Tricks ist die getEncosingMethod()Rückgabe, mit java.lang.reflect.Methodder alle anderen Informationen der Methode einschließlich Anmerkungen und Parameternamen abgerufen werden können. Dies ermöglicht die Unterscheidung zwischen gleichnamigen Methoden (Methodenüberladung).

Beachten Sie, dass laut JavaDoc getEnclosingMethod()dieser Trick kein a werfen sollteSecurityException da innere Klassen mit demselben Klassenlader geladen werden sollten. Daher müssen die Zugriffsbedingungen auch dann nicht überprüft werden, wenn ein Sicherheitsmanager vorhanden ist.

Es ist getEnclosingConstructor()für Konstruktoren erforderlich . Gibt bei Blöcken außerhalb von (benannten) Methoden getEnclosingMethod()zurück null.

Devin
quelle
9
Dadurch erhalten Sie keine aktuell ausgeführte Methode. Dadurch erhalten Sie die Methode, in der eine anonyme / lokale Klasse definiert ist. - docs.oracle.com/javase/6/docs/api/java/lang/…
shrini1000
7
Klasse Local {}; String name = Local.class.getEnclosingMethod (). GetName ();
Alexsmail
21
@ shrini1000 Die Idee ist, dieses Snippet dort zu verwenden, wo die Informationen benötigt werden, und es nicht in eine Bibliotheksroutine zu stellen.
Thorbjørn Ravn Andersen
4
Danke für die Tipps ! Anstatt ein neues Objekt zu erstellen, verwenden Sie einfach this.getClass (). GetEnclosingMethod (). GetName ();
Lilo
3
@ Lilo falsch. getEnclosingMethodRuft den Namen der Methode ab, in der die Klasse definiert ist. this.getClass()wird dir überhaupt nicht helfen. @wutzebaer warum brauchst du das überhaupt? Sie haben bereits Zugriff darauf.
Hazel Troost
134

Januar 2009:
Ein vollständiger Code wäre (unter Berücksichtigung der Einschränkung von @ 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
}

Mehr in dieser Frage .

Update Dezember 2011:

bläuliche Kommentare:

Ich verwende JRE 6 und gebe mir einen falschen Methodennamen.
Es funktioniert, wenn ich schreibeste[2 + depth].getMethodName().

  • 0ist getStackTrace(),
  • 1ist getMethodName(int depth)und
  • 2 ruft die Methode auf.

virgo47 ‚s Antwort (upvoted) berechnet tatsächlich den richtigen Index anzuwenden , um den Namen der Methode zurück zu bekommen.

VonC
quelle
2
Es heißt nur "main" für mich. : - /
Prof. Falken Vertrag verletzt
@Amigable: Haben Sie versucht, das gesamte StackTraceElementArray zum Debuggen zu drucken und festzustellen , ob 'main' tatsächlich die richtige Methode ist?
VonC
7
Ich verwende JRE 6 und gebe mir einen falschen Methodennamen. Es funktioniert, wenn ich schreibe ste[2 + depth].getMethodName(). 0 ist getStackTrace(), 1 ist getMethodName(int depth)und 2 ruft die Methode auf. Siehe auch die Antwort von @ virgo47 .
bläulich
2
@bluish: guter Punkt. Ich habe Ihren Kommentar und einen Verweis auf die Antwort von virgo47 in meinen aufgenommen.
VonC
@VonC Ist diese Implementierung wirklich korrekt? Die Tiefe muss hier ste.length + 1 sein, damit die aktuelle Methode angezeigt wird. Sollte es nicht ste [Tiefe + 1] sein, wenn wir Tiefe = 0 zulassen sollen?
mmm
85

Wir haben diesen Code verwendet, um die potenzielle Variabilität des Stack-Trace-Index zu verringern. Rufen Sie jetzt einfach methodName util auf:

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

Scheint überentwickelt, aber wir hatten eine feste Nummer für JDK 1.5 und waren etwas überrascht, dass sie sich geändert hat, als wir zu JDK 1.6 gewechselt sind. Jetzt ist es in Java 6/7 dasselbe, aber man weiß es einfach nie. Es ist kein Beweis für Änderungen in diesem Index zur Laufzeit - aber hoffentlich macht HotSpot das nicht schlecht. :-)

Jungfrau47
quelle
1
Dies ist immer noch subtil herstellerabhängig. Die JVM muss keine zuverlässigen Daten für diesen Code liefern.
Thorbjørn Ravn Andersen
6
Gemäß der JVM-Spezifikation muss die JVM keine vollständigen Stack-Traces (Optimierung, Inlining und so weiter) bereitstellen, und Sie haben bereits festgestellt, dass sich Ihre Heuristik zwischen Oracle Java 5 und Oracle Java 6 geändert hat. Es gibt keine Garantie dafür, dass eine andere JVM dies tut Verhalten Sie sich wie erwartet in Ihrem Code, sodass Sie sich subtil auf herstellerspezifisches Verhalten verlassen. Was vollkommen in Ordnung ist, solange Sie sich dessen bewusst sind, aber wenn Sie beispielsweise auf einer IBM JVM (die wir benötigen) oder auf einer Zing-Instanz bereitstellen müssen, müssen Sie möglicherweise Ihre Heuristik erneut überprüfen.
Thorbjørn Ravn Andersen
1
Dies scheint die robusteste aller hier vorgestellten Optionen zu sein, ungeachtet der Abhängigkeiten.
Ian
46
 public class SomeClass {
   public void foo(){
      class Local {};
      String name = Local.class.getEnclosingMethod().getName();
   }
 }

Name hat den Wert foo.

alexsmail
quelle
5
Local.class.getEnclosingMethod () war null. jdk1.6.0_31, spielen 1.2.5
eigil
@eigil das ist interessant, aber ohne weitere Informationen ist es schwer zu sagen, was "falsch" gelaufen ist oder wann wir erwarten solltennull
Maarten Bodewes
Dies ist der gleiche Trick wie diese Antwort . Es hat den Vorteil, dass keine falsche Objektinstanz erstellt wird, es hat den Nachteil, dass eine Klassendeklaration erforderlich ist, die nicht in die Anweisung eingefügt werden kann (dh normalerweise ist eine zusätzliche Codezeile erforderlich).
Maarten Bodewes
@eigil Haben Sie die Klasse innerhalb einer Klasse (Beispiel SomeClass) oder innerhalb einer Methode (Beispiel foo) definiert? Ich habe festgestellt, dass das Definieren einer Unterklasse, ohne in eine Methode oder einen Konstruktor eingeschlossen zu werden, dazu führt, dass getEnclosingMethod () null zurückgibt.
DN
Ich bin mir ziemlich sicher, dass ich genau das getan habe, was in dieser Antwort beschrieben wurde. Ich finde es etwas seltsam mit Playframework. Getestet in 'normalem' Java ohne Probleme.
Eigil
36

Beide Optionen funktionieren für mich mit Java:

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

Oder:

Thread.currentThread().getStackTrace()[1].getMethodName()
Charlie Seligman
quelle
1
Für statische Methoden verwenden Sie: <Klasse> .class.getEnclosingMethod (). getName ()
jellobird
Achten Sie auf leere Felder gemäß Bombes Antwort und Javadoc-Angabe. Einige JVM füllen das Stacktrace-Array möglicherweise nicht aus?
El-Teedee
34

Der schnellste Weg, den ich gefunden habe, ist folgender:

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

Es greift direkt auf die native Methode getStackTraceElement (int depth) zu. Und speichert die zugängliche Methode in einer statischen Variablen.


quelle
3
Am schnellsten wie in Bezug auf die Leistung? Gibt es einen Mikro-Benchmark, der die Behauptung stützt?
Ibrahim Arief
10
+1. Bei Verwendung einer einfachen zeitgesteuerten Schleife in 1.6 dauerten 1.000.000 Iterationen mit dieser Methode 1219 ms, während die Verwendung new Throwable().getStackTrace()5614 ms dauerte.
Ach
1
m.setAccessible (true); sollte von AccessController.doPrivileged umgeben sein. Etwas zu beachten, keine harte Regel würde ich sagen
avanderw
6
Getestet im Jahr 2016 und dies ist weiterhin die schnellste. Wie @ach habe ich 1M Iterationen verwendet. 1,7_79: 1,6 s gegen 15,2 s 1,8_74: 1,8 s gegen 16,0 s. FWIW die Länge meines Benchmark-Ste-Arrays == 23, aber diese Methode bleibt unabhängig von der Stapeltiefe schnell.
Ryan
25

Verwenden Sie den folgenden Code:

    StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
    StackTraceElement e = stacktrace[1];//coz 0th will be getStackTrace so 1st
    String methodName = e.getMethodName();
    System.out.println(methodName);
Sumit Singh
quelle
2
Dies druckt "getStackTrace" für mich aus - ich verwende Java 1.5
Zack Macomber
Achten Sie auf leere Felder gemäß Bombes Antwort und Javadoc-Angabe. Einige JVM füllen das Stacktrace-Array möglicherweise nicht aus?
El-Teedee
16
public static String getCurrentMethodName() {
        return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName();
    }
Jay
quelle
Ja, bei weitem das Beste ... verwandeln Sie es in eine Methode und erhalten Sie den dritten ([2]) Frame (oder wie auch immer er heißt) in der Ablaufverfolgung.
Mike Nagetier
14

Dies ist eine Erweiterung der Antwort von virgo47 (oben).

Es bietet einige statische Methoden, um die aktuellen und aufrufenden Klassen- / Methodennamen abzurufen.

/* 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
quelle
3
Dies ist in Kombination mit der Antwort von @ mklemenz eine sehr schnelle und saubere Möglichkeit, auf Stapelinformationen zuzugreifen.
Octavia Togami
12

Um den Namen der Methode zu erhalten, die die aktuelle Methode aufgerufen hat, können Sie Folgendes verwenden:

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

Dies funktioniert sowohl auf meinem MacBook als auch auf meinem Android-Handy

Ich habe auch versucht:

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

aber Android wird "getStackTrace" zurückgeben. Ich könnte dies für Android mit beheben

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

aber dann bekomme ich auf meinem MacBook die falsche Antwort

Friso van der Made
quelle
In den letzten Tests auf Android hat es für mich besser funktioniert, getStackTrace()[0]als zu verwenden getStackTrace()[1]. YMMV.
mbm29414
up für Android istThread.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
    }
}
Maxple
quelle
final StackTraceElement e = Thread.currentThread().getStackTrace()[2]; arbeitet; Geben Sie e.getClassName();den vollständigen Klassennamen und e.getMethodName()den Methonnamen zurück.
Marks
1
getStackTrace()[2]ist falsch, es muss sein, getStackTrace()[3]weil: [0] dalvik.system.VMStack.getThreadStackTrace [1] java.lang.Thread.getStackTrace [2] Utils.getCurrentClassAndMethodNames [3] Die Funktion a (), die diese aufruft
PhilLab
11

Dies kann StackWalkerseit Java 9 erfolgen.

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

StackWalkerist so konzipiert, dass es faul ist, daher ist es wahrscheinlich effizienter als beispielsweise Thread.getStackTraceein Array für den gesamten Callstack. Weitere Informationen finden Sie auch im JEP.

Radiodef
quelle
5

Eine alternative Methode besteht darin, eine Ausnahme zu erstellen, aber nicht auszulösen und das Objekt zu verwenden, von dem die Stack-Trace-Daten abgerufen werden, da die einschließende Methode dies normalerweise tut den Index 0 hat - solange die JVM diese Informationen speichert, wie andere oben erwähnt. Dies ist jedoch nicht die billigste Methode.

Von Throwable.getStackTrace () (dies ist mindestens seit Java 5 dasselbe):

Das nullte Element des Arrays (unter der Annahme, dass die Länge des Arrays nicht Null ist) repräsentiert die Oberseite des Stapels. Dies ist der letzte Methodenaufruf in der Sequenz. In der Regel ist dies der Punkt, an dem dieses Wurfobjekt erstellt und geworfen wurde.

Das folgende Snippet geht davon aus, dass die Klasse nicht statisch ist (aufgrund von getClass ()), aber das ist eine Seite.

System.out.printf("Class %s.%s\n", getClass().getName(), new Exception("is not thrown").getStackTrace()[0].getMethodName());
Jool
quelle
4
String methodName =Thread.currentThread().getStackTrace()[1].getMethodName();
System.out.println("methodName = " + methodName);
lief
quelle
1
Siehe Antworten von mvanle virgo47 oben und Kommentar von thorbjorn-ravn-andersen. Wiederholter, nicht genauer und nicht zuverlässiger Code.
Alexsmail
@ShivaKomuravelly Ja, aber es scheint in keiner Situation so, -1 auch von mir.
Maarten Bodewes
3

Ich habe eine Lösung mit diesem (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())}));
    }
}
Kasim Rangwala
quelle
3

Ich weiß nicht, was die Absicht ist, den Namen der aktuell ausgeführten Methode zu erhalten, aber wenn dies nur zum Debuggen dient, können Protokollierungsframeworks wie "logback" hier helfen. Bei der Rückmeldung müssen Sie beispielsweise nur das Muster "% M" in Ihrer Protokollierungskonfiguration verwenden . Dies sollte jedoch mit Vorsicht angewendet werden, da dies die Leistung beeinträchtigen kann.

James Selvakumar
quelle
2

Nur für den Fall, dass die Methode, deren Namen Sie kennen möchten, eine Junit-Testmethode ist, können Sie die Junit-TestName-Regel verwenden: https://stackoverflow.com/a/1426730/3076107

Egl
quelle
1
@AndreiKonstantinov Ich glaube nicht, dass dies nur ein Link ist. Selbst wenn Sie den Link entfernen, müssen noch einige Informationen angezeigt werden.
EJoshuaS
1

Die meisten Antworten hier scheinen falsch zu sein.

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

Beispiel:

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

Ausgänge:

aaa  -> aaa
aaa  -> aaa
main -> main
mmm
quelle
Vielen Dank für Ihre nützliche Antwort.
AmerllicA
Könnten Sie bitte klarstellen, warum die meisten Antworten für Sie falsch erscheinen? Es gibt viele Antworten und ich bin nicht so gut mit Java vertraut, um alle zu lesen und zu verstehen, was der Unterschied zwischen ihnen und Ihrer Antwort ist. :(
Xobotun
@mmm Sorry, aber ich bin absolut anderer Meinung. Ich komme hierher, um zu lernen, und viele andere auch, glaube ich. Ich kann einfach nicht verstehen, warum ich glaube, ich habe es nicht verdient, mehr über dieses Thema zu erfahren. Ich möchte weniger Fehler in meinem Code machen und andere warnen, nicht einem Frachtkult folgen. Sie hätten zumindest klarstellen können, auf welcher Java-Version dieser Code korrekt sein sollte. :( Eine Antwort unten besagt, dass sich die Stapelverfolgung zwischen 1,5 und 1,6 geändert hat. Vielleicht implizieren Sie, dass es im kommenden Java 14 so etwas gibt, wie kann ich das wissen. Oder ein anderer Anbieter hat es getan. Tut mir leid, wenn ich Ihre Antwort als unhöflich interpretiert habe Eins.
Xobotun
0

Ich habe die Antwort des Maklemenz ein wenig umgeschrieben :

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);
}
Marco Sulla
quelle
-2
MethodHandles.lookup().lookupClass().getEnclosingMethod().getName();
Darren
quelle
11
Bitte bearbeiten Sie mit weiteren Informationen. Nur-Code- und "Versuch dies" -Antworten werden nicht empfohlen, da sie keinen durchsuchbaren Inhalt enthalten und nicht erklären, warum jemand "dies versuchen" sollte.
Abarisone
1
Obwohl dieser Code zur Lösung des Problems beitragen kann, erklärt er nicht, warum und / oder wie er die Frage beantwortet. Die Bereitstellung dieses zusätzlichen Kontextes würde den langfristigen Bildungswert erheblich verbessern. Bitte bearbeiten Sie Ihre Antwort, um eine Erklärung hinzuzufügen, einschließlich der Einschränkungen und Annahmen.
Toby Speight
1
Nur für Java 7+, aber prägnanter Weg, um den Methodennamen zu erhalten. Dennoch bleiben die Leistungsüberlegungen eines solchen Anrufs.
Benj
6
getEnclosingMethod()wirft ein NullPointerExceptionfür mich in Java 7.
Markus L
2
Die Datei java.lang.Class.getEnclosingMethod () gibt ein Methodenobjekt zurück, das die unmittelbar einschließende Methode der zugrunde liegenden Klasse darstellt. Wenn dieses Klassenobjekt eine lokale oder anonyme Klasse innerhalb einer Methode darstellt, gibt andernfalls null zurück.
Herd
-5

Was ist falsch an diesem Ansatz:

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

Und bevor die Leute verrückt nach der Verwendung werden System.out.println(...), können und sollten Sie immer eine Methode erstellen, damit die Ausgabe umgeleitet werden kann, z.

    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());
        }
    }
Johnny
quelle
4
@ Saksham es sieht für mich so aus, als wäre das eigentlich ein Versuch, die Frage zu beantworten. Kein großer Versuch, aber dennoch ein Versuch.
ivarni
@ivarni "kein guter Versuch"? Was stimmt damit nicht? Kennen Sie das "Kussprinzip"?
Johnny
@ Saksham es war rhetorisch.
Johnny
5
@johnny In der Codebasis, die ich gerade vor mir habe, gibt es 271 Klassen. Selbst mit einer (niedrigen Schätzung) von 5 Methoden pro Klasse sind das über 1300 Methoden. Und das ist nicht einmal eine große Codebasis. Sie sehen das Problem bei der Skalierung Ihres Ansatzes nicht? Ich bin ziemlich glücklich zuzustimmen, nicht zuzustimmen, aber deshalb habe ich gesagt, dass es kein guter Versuch ist. Es führt zu einem enormen Overhead in jeder nicht trivialen Codebasis.
ivarni
1
@johnny Ich glaube, ich habe zu viele Fälle gesehen, in denen der Methodenname nicht mit der Zeichenfolge übereinstimmt, die mich beim Debuggen in die falsche Richtung geschickt hat. Aber in Java denke ich immer noch, dass Ihr Vorschlag der beste ist, die anderen Alternativen "kosten" zu viel.
Nur ein weiterer Metaprogrammer