Getting the name of the currently executing method
有没有办法在Java中获取当前执行方法的名称?
从技术上讲,这是可行的…
号
但是,在编译期间将创建一个新的匿名内部类(例如
这个技巧的一个优点是,
注意,根据
施工人员使用
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.
号
2009年1月:完整的代码应该是(考虑到@bombe的警告):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /** * 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 } |
关于这个问题的更多信息。
2011年12月更新:
蓝色评论:
I use JRE 6 and gives me incorrect method name.
It works if I writeste[2 + depth].getMethodName().
0 isgetStackTrace() ,1 isgetMethodName(int depth) and2 is invoking method.
号
Virgo47的答案(上票)实际上计算了要应用的正确索引,以便返回方法名。
我们使用此代码来减轻堆栈跟踪索引中的潜在变化性-现在只需调用methodname-util:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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(); } } |
似乎设计得太过分了,但JDK1.5有一些固定的数字,当我们移到JDK1.6时,它发生了一些变化,这让我们有点惊讶。现在在Java 6/7中是一样的,但是你永远不知道。它并不能证明在运行时该索引发生了变化,但希望Hotspot不会那么糟糕。-)
1 2 3 4 5 6 | public class SomeClass { public void foo(){ class Local {}; String name = Local.class.getEnclosingMethod().getName(); } } |
。
名称将具有值foo。
这两个选项都适用于Java:
1 |
号
或:
1 |
号
我发现最快的方法是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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; } } } |
它直接访问本机方法getstacktraceelement(int depth)。并将可访问方法存储在静态变量中。
使用以下代码:
1 2 3 4 |
。
1 2 3 |
。
这是对Virgo47答案的扩展(见上文)。
它提供了一些静态方法来获取当前和调用类/方法名称。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | /* 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 +")"; } } |
。
要获取调用当前方法的方法的名称,可以使用:
1 |
号
它既适用于我的MacBook,也适用于我的Android手机
我也试过:
1 |
号
但Android会返回"getstacktrace"我可以用
1 |
号
但是我在我的笔记本上得到了错误的答案
java实用程序:
1 2 3 4 5 |
号
someclass.java:Java语言:
1 2 3 4 5 |
号
1 2 |
这可以从使用Java 9以来使用EDCOX1 0来完成。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
另一种方法是创建(而不是抛出)异常,并使用从中获取堆栈跟踪数据的对象,因为封闭方法通常位于索引0处——只要JVM存储这些信息,如前面提到的那样。然而,这不是最便宜的方法。
从JavaLab.GETStAccTrace.()(这至少在Java 5之后是相同的):
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.
号
下面的代码段假定类是非静态的(因为getClass()),但这是一个旁白。
1 2 |
号
我有使用这个的解决方案(在Android中)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /** * @param className fully qualified className * <br/> * <wyn>YourClassName.class.getName();</wyn> * <br/><br/> * @param classSimpleName simpleClassName * <br/> * <wyn>YourClassName.class.getSimpleName();</wyn> * <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())})); } } |
号
我不知道获取当前执行的方法名称背后的意图是什么,但是如果这只是为了调试,那么像"logback"这样的日志框架可以在这里有所帮助。例如,在logback中,您所需要做的就是在日志配置中使用模式"%m"。但是,应小心使用,因为这可能会降低性能。
1 | MethodHandles.lookup().lookupClass().getEnclosingMethod().getName(); |
如果您想知道的方法是JUnit测试方法,那么可以使用JUnit测试名称规则:https://stackoverflow.com/a/1426730/3076107
这种方法有什么问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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); } } |
在人们疯狂使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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()); } } |
。