茫茫網海中的冷日 - 對這文章發表回應
茫茫網海中的冷日
         
茫茫網海中的冷日
發生過的事,不可能遺忘,只是想不起來而已!
 恭喜您是本站第 1672095 位訪客!  登入  | 註冊
主選單

Google 自訂搜尋

Goole 廣告

隨機相片
HoneyMoon_Day1_00026.jpg

授權條款

使用者登入
使用者名稱:

密碼:


忘了密碼?

現在就註冊!

對這文章發表回應

發表限制: 非會員 可以發表

發表者: 冷日 發表時間: 2019/4/2 6:10:17
Getting the name of the currently executing method

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



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.



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 getEncosingMethod() 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.
It is required to use getEnclosingConstructor() for constructors. During blocks outside of (named) methods, getEnclosingMethod() returns null.



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.



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. :-)



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

name will have value foo.



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.



Both of these options work for me with Java:
new Object(){}.getClass().getEnclosingMethod().getName()

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




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




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




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




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



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




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




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




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




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.



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



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.



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




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


原文出處:java - Getting the name of the currently executing method - Stack Overflow
內容圖示
url email imgsrc image code quote
樣本
bold italic underline linethrough   












 [詳情...]
validation picture

注意事項:
預覽不需輸入認證碼,僅真正發送文章時才會檢查驗證碼。
認證碼有效期10分鐘,若輸入資料超過10分鐘,請您備份內容後,重新整理本頁並貼回您的內容,再輸入驗證碼送出。

選項

Powered by XOOPS 2.0 © 2001-2008 The XOOPS Project|