Java:如何获取调用函数名

rjjhvcjd  于 2023-03-11  发布在  Java
关注(0)|答案(8)|浏览(132)

为了修正一个测试用例,我需要确定这个函数是否是从一个特定的调用函数调用的。我不能添加一个布尔参数,因为它会破坏定义的接口。如何进行呢?
这就是我想要实现的,这里我不能修改operation()的参数,因为它是一个接口实现。

operation()
{
   if not called from performancetest() method
       do expensive bookkeeping operation
   ...       

}
wqsoz72f

wqsoz72f1#

你可以试试

StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
String methodName = e.getMethodName();
6za6bjd0

6za6bjd02#

下面是一些更现代(Java 9+中提供)、性能更好的代码。

private static String getCallerMethodName()
{
   return StackWalker.
      getInstance().
      walk(stream -> stream.skip(1).findFirst().get()).
      getMethodName();
}

根据需要将skip(1)更改为更大的数字,以便在堆栈中更高。
这比Thread.currentThread().getStackTrace()执行得更好,因为它不遍历整个堆栈并分配所有堆栈帧,它只遍历堆栈上的两个帧。
此方法可以调整为返回StackWalker.StackFrame,其中包含有关该方法的大量信息。

slsn1g29

slsn1g293#

我写了一个函数,记录调用它的函数的函数名。它沿着堆栈跟踪向上运行,直到找到一个名为logIt的函数,然后显示下一个函数名。这是一个肮脏的黑客,所以除非你用它来调试,否则不要这样做。

private static void logIt() {
    StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
    boolean logged = false;
    boolean foundMe = false;
    for(int i=0; i<stacktrace.length; i++) {
        StackTraceElement e = stacktrace[i];
        String methodName = e.getMethodName();
        if (foundMe) {
            if (!methodName.startsWith("access$")) {
                Log.i(TAG, String.format(Locale.US, "%s.%s", e.getClassName(), methodName));
                logged = true;
                break;
            }
        } else {
            if (methodName.equals("logIt")) {
                foundMe = true;
            }
        }
    }
    if (!logged)
        Log.e(TAG, "unlogged call");
}
4dc9hkyq

4dc9hkyq4#

我调整了这里讨论的代码,并定制它来获取调用方法。这里的代码所做的是迭代堆栈跟踪元素,一旦它找到被调用方法的名称,它就获取前一个方法的名称,而前一个方法又将是调用该方法的方法。

private String method() {
    String methodName=null;
    StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
    for (int i = 0; i < stacktrace.length; i++) {
        if(stacktrace[i].getMethodName().equals("method")) {
            methodName = stacktrace[i+1].getMethodName();
            break;
        }
    }
      return methodName;

}
lf5gs5x2

lf5gs5x25#

另一个安卓使用示例:

//package your.package.name;
import android.util.Log;
/*
 File name: MyDebugLog.java
*/
public class MyDebugLog {
    private static final int    index      = 4;     // <== Index in call stack array
    private static final String methodName = "Log"; // <== Name of method for public call
    private static String getCallerName() {
        String caller = "NONE";
        final StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
        for (int i = 0; i < stacktrace.length; i++) {
            Log.e("Method ", "[" + i + "]" + stacktrace[i].getMethodName());
        }
        if (stacktrace.length >= index){
            caller = stacktrace[index].getMethodName();
        }
        return caller;
    }

    private static String getTag() {
        String tag = "NONE";
        final StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
        for (int i = 0; i < stacktrace.length; i++) {
            Log.e("Method ", "[" + i + "]" + stacktrace[i].getMethodName());
            if (stacktrace[i].getMethodName().equals(methodName)) {
                tag = "("+stacktrace[i + 1].getFileName() + ":" + stacktrace[i + 1].getLineNumber()+")";
                return tag;
            }
        }
        return tag;
    }

    public static void Log(String message){
        Log.v(getTag(), getCallerName() + " " + message);
    }
}

用法:

@Override
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.sample_main);
            MyDebugLog.Log("XXXXX");
    }

输出:

V/(MainActivity.java:117): onCreate XXXXX

阵列示例:

getTag Sample of stacktace array:

    Method: [0]getThreadStackTrace
    Method: [1]getStackTrace
    Method: [2]getTag
    Method: [3]Log                 <== Method for external call
    ...
 getName Sample of stacktace array:
    Method: [0]getThreadStackTrace
    Method: [1]getStackTrace
    Method: [2]getCallerName
    Method: [3]Log
    Method: [4]onCreate            <== Our external method
    Method: [5]performCreate
    ...
yxyvkwin

yxyvkwin6#

有时候我想向logcat输出一些东西,所以我写了一个包含一些测试方法的小类:

public class Common {

    // can be used as test-flag anywhere in the app (set to false, when release the app)
    public static boolean b_TEST_MODE = true;

    public static void echo(String message) {
        if (b_TEST_MODE) {
            StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
            // subtring(25) is to cut off app-name from output
            System.out.println(">>> " + stackTraceElements[3].toString().substring(25) + ": " + message);
        }
    }
}

现在,您可以从应用程序中的任何位置调用它来获取一些信息:

String sSQLQuery = "SELECT * FROM database WHERE id=23";
Common.echo(sSQLQuery);

logcat打印输出:

>>> MainActivity.onCreate(MainActivity.java:46): SELECT * FROM dateabase WHERE id=23
a64a0gku

a64a0gku7#

我不知道为什么,但是在我的工作中,开发系统与测试和生产环境不同,在堆栈中移动位置。我被迫在堆栈中循环,以从堆栈跟踪中的下一个元素中找到并获得调用方法。有点笨重,但到目前为止一直返回所需的方法。我使用这作为错误处理的一部分,以确定在哪里捕获了异常。

List<String> list = new ArrayList<String>();
    StackTraceElement[] elements = Thread.currentThread().getStackTrace();
    for (int i = 0; i < Thread.currentThread().getStackTrace().length; i++) {
        System.out.println("Stack: "
                + i
                + " Class: "
                + elements[i].getClassName()
                + " Method: "
                + elements[i].getMethodName());
        if (elements[i].getMethodName().equals("<init>")) {
            list.add(elements[i + 1].getClassName());
            list.add(elements[i + 1].getMethodName());
             break;
        } // if
    } // for
aor9mmx1

aor9mmx18#

通过更改索引值检查以下行:

System.out.println("Name of Caller method:" 
+ new Throwable().getStackTrace()[1].getMethodName());

    System.out.println("Name of Current method:" 
+ new Throwable().getStackTrace()[0].getMethodName());

相关问题