ChatGPT解决这个技术问题 Extra ChatGPT

Getting the name of the currently executing method

Is there a way to get the name of the currently executing method in Java?


p
pocketrocket

Technically this will work...

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

However, a new anonymous inner class will be created during compile time (e.g. YourClass$1.class). So this will create a .class file for each method that deploys this trick. Additionally, an otherwise unused object instance is created on each invocation during runtime. So this may be an acceptable debug trick, but it does come with significant overhead.

An advantage of this trick is that getEnclosingMethod() returns java.lang.reflect.Method which can be used to retrieve all other information of the method including annotations and parameter names. This makes it possible to distinguish between specific methods with the same name (method overload).

Note that according to the JavaDoc of getEnclosingMethod() this trick should not throw a SecurityException as inner classes should be loaded using the same class loader. So there is no need to check the access conditions even if a security manager is present.

Please be aware: It is required to use getEnclosingConstructor() for constructors. During blocks outside of (named) methods, getEnclosingMethod() returns null.


This won't give you currently executing method. This will give you that method in which an anonymous/local class is defined. - docs.oracle.com/javase/6/docs/api/java/lang/…
class Local {}; String name = Local.class.getEnclosingMethod().getName();
@shrini1000 the idea is to use this snippet where the information is needed, and not put it in a library routine.
Thanks for the tips ! Instead of creating a new object, just use this.getClass().getEnclosingMethod().getName();
@Lilo incorrect. getEnclosingMethod gets the name of the method where the class is defined. this.getClass() won't help you at all. @wutzebaer why would you even need to? You have access to them already.
r
randers

Thread.currentThread().getStackTrace() will usually contain the method you’re calling it from but there are pitfalls (see Javadoc):

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


Is this same pitfall true for stack traces in exceptions?
Yes, it is. The documentation for Throwable.[getStackTrace()](download.oracle.com/javase/1.5.0/docs/api/java/lang/… contains the exact same paragraph.
The underlying thing is that the JVM is not required to be able to provide a stacktrace, but that a lot of work has gone into making HotSpot very reliable. You need to know, though, in case you want your code to not rely on the behavior of a specific JVM.
Alexsmail's version below does not create a stack trace and gives you access to the actual method object, not just the name (so you can find out return type too). I haven't bench marked but I suspect his method is much faster too since stack traces tend to be expensive.
C
Community

January 2009:
A full code would be (to use with @Bombe's caveat in mind):

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

More in this question.

Update December 2011:

bluish comments:

I use JRE 6 and gives me incorrect method name. It works if I write ste[2 + depth].getMethodName(). 0 is getStackTrace(), 1 is getMethodName(int depth) and 2 is invoking method.

virgo47's answer (upvoted) actually computes the right index to apply in order to get back the method name.


It only says "main" for me. :-/
@Amigable: did you try to print the all StackTraceElement array for debugging purpose and to see if 'main' is actually the right method?
I use JRE 6 and gives me incorrect method name. It works if I write ste[2 + depth].getMethodName(). 0 is getStackTrace(), 1 is getMethodName(int depth) and 2 is invoking method. See also @virgo47's answer.
@bluish: good point. I have included your comment and a reference to virgo47's answer in mine.
@VonC Is this implementation really correct? depth here must be ste.length + 1 for that to give current method. Should it not be ste[depth + 1] if we are to allow depth = 0 ?
v
virgo47

We used this code to mitigate potential variability in stack trace index - now just call 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();
    }
}

Seems overengineered, but we had some fixed number for JDK 1.5 and were a bit surprised it changed when we moved to JDK 1.6. Now it's the same in Java 6/7, but you just never know. It is not proof to changes in that index during runtime - but hopefully HotSpot doesn't do that bad. :-)


This is still subtly vendor dependent. The JVM is not required to deliver reliable data for this code.
Per the JVM spec the JVM is not required to provide full stack traces (optimization, inlining and all that) and you've already discovered that your heuristic changed between Oracle Java 5 and Oracle Java 6. There is nothing guaranteeing that any other JVM will behave as you expect in your code, so you are subtly relying on vendor specific behavior. Which is perfectly fine, as long as you are aware of that, but if - for instance - you need to deploy on an IBM JVM (which we must) or on a Zing instance you may have to revisit your heuristic.
This seems the most robust of all the options presented here, dependencies notwithstanding.
a
alexsmail
 public class SomeClass {
   public void foo(){
      class Local {};
      String name = Local.class.getEnclosingMethod().getName();
   }
 }

name will have value foo.


Local.class.getEnclosingMethod() was null. jdk1.6.0_31, play 1.2.5
@eigil that's interesting but without more info it is hard to tell what went "wrong" or when we should expect null
This is the same trick as this answer. It has the advantage that it does not create a spurious object instance, it has the disadvantage that it requires a class declaration which cannot be inlined in the statement (i.e. normally it requires an additional line of code).
@eigil did you define the class within a class (example SomeClass), or within a method (example foo)? I found that defining a subclass without being wrapped in a method - or in a constructor - will cause getEnclosingMethod() to return null.
Pretty sure I did exactly as described in this answer. I think it's something strange with playframework. Tested in 'normal' java without any problem.
C
Charlie Seligman

Both of these options work for me with Java:

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

Or:

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

for static methods use: .class.getEnclosingMethod().getName()
be carefull of empty array according to Bombe's answer and javadoc indication. Some JVM may not fill the stacktrace array?
佚名

The fastest way I found is that:

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

It accesses the native method getStackTraceElement(int depth) directly. And stores the accessible Method in a static variable.


Fastest as in performance wise? Any micro-benchmark to support the claim?
+1. Using a simple timed loop on 1.6, 1,000,000 iterations using this method took 1219ms, while using new Throwable().getStackTrace() took 5614ms.
m.setAccessible(true); should be surrounded by AccessController.doPrivileged. Something to consider, not a hard rule I would say
Tested in 2016 and this continues to be the fastest. Like @ach I used 1M iterations. 1.7_79: 1.6s vs 15.2s 1.8_74: 1.8s vs 16.0s. FWIW my benchmark ste array's length==23 but this method stays fast regardless of stack depth.
R
Radiodef

This can be done using StackWalker since Java 9.

public static String getCurrentMethodName() {
    return StackWalker.getInstance()
                      .walk(s -> s.skip(1).findFirst())
                      .get()
                      .getMethodName();
}

public static String getCallerMethodName() {
    return StackWalker.getInstance()
                      .walk(s -> s.skip(2).findFirst())
                      .get()
                      .getMethodName();
}

StackWalker is designed to be lazy, so it's likely to be more efficient than, say, Thread.getStackTrace which eagerly creates an array for the entire callstack. Also see the JEP for more information.


S
Sumit Singh

Use the following 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);

This prints off "getStackTrace" for me - I'm using Java 1.5
be carefull of empty array according to Bombe's answer and javadoc indication. Some JVM may not fill the stacktrace array?
M
Micha Wiedenmann
public static String getCurrentMethodName() {
        return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName();
    }

Yes, by far the best... turn it into a method and get the third ([2]) frame (or whatever it's called) in the trace.
C
Community

This is an expansion on virgo47's answer (above).

It provides some static methods to get the current and invoking class / method names.

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

This in combination with @mklemenz's answer is a very fast and clean way to access stack info.
F
Friso van der Made

To get the name of the method that called the current method you can use:

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

This works on my MacBook as well as on my Android phone

I also tried:

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

but Android will return "getStackTrace" I could fix this for Android with

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

but then I get the wrong answer on my MacBook


In recent testing on Android, it worked better for me to use getStackTrace()[0] rather than getStackTrace()[1]. YMMV.
up for android is Thread.currentThread().getStackTrace()[2]
M
Maxple

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]; works; e.getClassName(); return the full class name and e.getMethodName() return the methon name.
getStackTrace()[2] is wrong, it has to be getStackTrace()[3] because: [0] dalvik.system.VMStack.getThreadStackTrace [1] java.lang.Thread.getStackTrace [2] Utils.getCurrentClassAndMethodNames [3] The function a() calling this one
J
Jool

An alternative method is to create, but not throw, an Exception, and use that object from which to get the stack trace data, since the enclosing method will typically be at index 0 - as long as the JVM stores that information, as others have mentioned above. This not the cheapest method, however.

From Throwable.getStackTrace() (this has been the same since Java 5 at least):

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

The snippet below assumes the class is non-static (because of getClass()), but that's an aside.

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

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

See answers of mvanle virgo47 above and comment of thorbjorn-ravn-andersen. Repetion, non-accurate and non-reliable code.
@ShivaKomuravelly Yes, but not in any situation it seems, so -1 from me as well.
K
Kasim Rangwala

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

C
Community

I don't know what is the intention behind getting the currently executed method's name, but if that's just for debugging purpose, then logging frameworks like "logback" can help here. For example, in logback, all you need to do is to use the pattern "%M" in your logging configuration. However, this should be used with caution as this may degrade performance.


E
Egl

Just in case the method which name you want to know is a junit test method, then you can use junit TestName rule: https://stackoverflow.com/a/1426730/3076107


@AndreiKonstantinov I don't think that this is link-only. Even if you remove the link, there's still at least some information to go on.
m
mjs

Most answers here seems wrong.

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

Example:

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

Outputs:

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

Could you please clarify why do most answer seem wrong for you? There are many answers and I'm not that well-versed in Java to read all of them and to understand what's the difference between them and your answer. :(
@mmm Sorry, but I strongly disagree. I come here to learn and so do many others, I believe. I just cannot understand why do you think I don't deserve to know more on this subject. I want to make less mistakes in my code and to warn others, not to follow some cargo-cult. You could've at least clarified what Java version this code should be correct on. :( An answer below says there was a change in stacktrace between 1.5 and 1.6. Maybe you imply there's something like that in the upcoming Java 14, how can I know. Or different vendor may have. Sorry if I misinterpreted your answer as a rude one.
f
fix

I use this code snippet with the latest Android Studio with the latest Java update. It can be called from any Activity, Fragment, etc.

public static void logPoint() {
    String[] splitPath = Thread.currentThread().getStackTrace()[3]
        .toString().split("\\.");

    Log.d("my-log", MessageFormat.format("{0} {1}.{2}",
        splitPath[splitPath.length - 3],
        splitPath[splitPath.length - 2],
        splitPath[splitPath.length - 1]
    ));
}

call it like this

logPoint();

output

... D/my-log: MainActivity onCreate[(MainActivity.java:44)]

M
Marco Sulla

I rewritten a little the maklemenz's answer:

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


D
Darren
MethodHandles.lookup().lookupClass().getEnclosingMethod().getName();

Please edit with more information. Code-only and "try this" answers are discouraged, because they contain no searchable content, and don't explain why someone should "try this".
Although this code may help to solve the problem, it doesn't explain why and/or how it answers the question. Providing this additional context would significantly improve its long-term educational value. Please edit your answer to add explanation, including what limitations and assumptions apply.
Only for Java 7+, but concise way to get the method name. Still, remains the performance considerations of such a call.
getEnclosingMethod() throws a NullPointerException for me in Java 7.
The java.lang.Class.getEnclosingMethod() returns a Method object representing the immediately enclosing method of the underlying class, if this Class object represents a local or anonymous class within a method, else returns null.
S
Steve Vinoski

What's wrong with this approach:

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

And before people go crazy about using System.out.println(...) you could always, and should, create some method so that output can be redirected, e.g:

    private void debug (Object object) {
        debug(object,true);
    }

    private void dedub(Object object, boolean debug) {
        if (debug) {
            System.out.println(object);

            // you can also write to a file but make sure the output stream
            // ISN'T opened every time debug(Object object) is called

            fileOutputStream.write(object.toString().getBytes());
        }
    }

@Saksham it looks to me like that was actually an attempt to answer the question. Not a great attempt, but an attempt none the less.
@ivarni "not a good attempt"? whats wrong with it? are you familiar with the "kiss principle"?
@johnny In the codebase I have in front of me right now there are 271 classes. Even with a (low estimate) og 5 methods per class that's over 1300 methods. And this is not even a big codebase. You don't see the problem with scaling up your approach? I'm quite happy to agree to disagree, but that's why I said it's not a good attempt. It introduces a massive amount of overhead in any non-trivial codebase.
@ivarni wouldnt you have to include a method call in each method (as suggested above) to perform the same and LESS reliable functon?
@johnny I guess I have seen too many cases where the method name doesn't match the string which have sent me in the wrong direction when debugging. But in Java I still think your suggestion is the best, the other alternatives "cost" too much.