Java:如何获取调用者函数名称

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4065518/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 11:10:35  来源:igfitidea点击:

Java: How to get the caller function name

javaunit-testing

提问by devnull

To fix a test case I need to identify whether the function is called from a particular caller function. I can't afford to add a boolean parameter because it would break the interfaces defined. How to go about this?

要修复测试用例,我需要确定该函数是否是从特定调用方函数调用的。我不能添加布尔参数,因为它会破坏定义的接口。如何解决这个问题?

This is what I want to achieve. Here I can't change the parameters of operation() as it is an interface implementation.

这就是我想要达到的目标。这里我不能更改 operation() 的参数,因为它是一个接口实现。

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

}

采纳答案by thejh

You could try

你可以试试

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

回答by JohnnyLambada

Here's a function I wrote to Log the function name of the function that calls it. It runs up the stack trace until it finds a function named logIt, then displays the next name. It's a dirty hack, so don't do it unless you're using it to debug.

这是我写的一个函数,用于记录调用它的函数的函数名称。它运行堆栈跟踪,直到找到名为 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");
}

回答by 0x8BADF00D

Another sample for android usage:

另一个android使用示例:

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

Usage:

用法:

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

Output:

输出:

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

Sample of arrays:

数组示例:

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

回答by prakash krishnan

I tweaked the code that is being discussed here and customized it to get the invoking method. What the code does here is to iterate over the stack trace elements and as soon as it finds the name of the method being invoked, it gets the name of the previous method, which in turn will be the method that is invoking this method.

我调整了此处讨论的代码并对其进行了自定义以获取调用方法。代码在这里所做的是迭代堆栈跟踪元素,一旦找到被调用的方法的名称,它就会获取前一个方法的名称,这将是调用此方法的方法。

    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;

}

回答by Martin

I sometimes want to make some outputs to the logcat. So I wrote a tiny class with some testing-methods:

有时我想对 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);
        }
    }
}

now you can call it from anywhere in the app to get some infos:

现在你可以从应用程序的任何地方调用它来获取一些信息:

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

The logcat prints out:

logcat 打印出:

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

回答by David D

I have no idea why but in my shop the develop system differs from the test and production environments shifting position in the stack. I was forced to loop through the stack to find and get the calling method from the next element in the stack trace. A little clunkier but so far has been consistently returning the desired method. I use this as part of my error handling to identify where an exception was caught.

我不知道为什么,但在我的商店中,开发系统不同于测试和生产环境在堆栈中移动位置。我被迫遍历堆栈以从堆栈跟踪中的下一个元素中查找并获取调用方法。有点笨重,但到目前为止一直在返回所需的方法。我使用它作为我的错误处理的一部分来识别异常被捕获的位置。

    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