Есть ли способ получить имя текущего исполняемого метода в Java?
Получение имени текущего исполняемого метода
Ответ 1
Thread.currentThread().getStackTrace()
обычно содержит метод, из которого вы вызываете его, но есть подводные камни (см. Javadoc):
Некоторые виртуальные машины могут при некоторых обстоятельствах пропустить один или несколько стековых фреймов из трассировки стека. В крайнем случае виртуальной машине, у которой нет информации трассировки стека относительно этого потока, разрешено возвращать массив нулевой длины из этого метода.
Ответ 2
Технически это будет работать...
String name = new Object(){}.getClass().getEnclosingMethod().getName();
Однако во время компиляции будет создан новый анонимный внутренний класс (например, YourClass$1.class
). Таким образом, это создаст файл .class
для каждого метода, который развертывает этот трюк. Кроме того, в каждом вызове во время выполнения создается другой неиспользуемый экземпляр объекта. Таким образом, это может быть приемлемым отладочным трюком, но на него накладываются значительные накладные расходы.
Преимущество этого трюка заключается в том, что getEncosingMethod()
возвращает java.lang.reflect.Method
, который может использоваться для извлечения всей другой информации метода, включая аннотации и имена параметров. Это позволяет различать конкретные методы с одним и тем же именем (метод перегрузки).
Обратите внимание, что в соответствии с JavaDoc getEnclosingMethod()
этот трюк не должен бросать SecurityException
, поскольку внутренние классы должны быть загружены с использованием одного и того же загрузчика классов. Поэтому нет необходимости проверять условия доступа, даже если присутствует менеджер безопасности.
Для конструкторов требуется использовать getEnclosingConstructor()
. Во время блоков вне (названных) методов getEnclosingMethod()
возвращает null
.
Ответ 3
Январь 2009:
Полный код будет (использовать с @Bombe caveat в виду):
/**
* 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:
bluish комментарии:
Я использую JRE 6 и даю мне неправильное имя метода.
Он работает, если я пишуste[2 + depth].getMethodName().
0
-getStackTrace()
,1
-getMethodName(int depth)
и2
вызывает метод.
virgo47 answer (upvoted) фактически вычисляет нужный индекс для применения, чтобы вернуться имя метода.
Ответ 4
Мы использовали этот код для смягчения потенциальной изменчивости индекса стека трассировки - теперь просто вызовите методName 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();
}
}
Кажется, слишком сложно, но у нас было некоторое фиксированное количество для JDK 1.5, и они немного удивили его, когда мы перешли на JDK 1.6. Теперь это то же самое в Java 6/7, но вы просто не знаете. Это не является доказательством изменений в этом индексе во время выполнения, но, надеюсь, HotSpot не делает этого плохо.: -)
Ответ 5
public class SomeClass {
public void foo(){
class Local {};
String name = Local.class.getEnclosingMethod().getName();
}
}
имя будет иметь значение foo.
Ответ 6
Самый быстрый способ, который я нашел, заключается в следующем:
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). И сохраняет доступный метод в статической переменной.
Ответ 7
Оба этих параметра работают для меня с Java:
new Object(){}.getClass().getEnclosingMethod().getName()
Или:
Thread.currentThread().getStackTrace()[1].getMethodName()
Ответ 8
Используйте следующий код:
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[1];//coz 0th will be getStackTrace so 1st
String methodName = e.getMethodName();
System.out.println(methodName);
Ответ 9
public static String getCurrentMethodName() {
return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName();
}
Ответ 10
Это расширение на ответ virgo47 (выше).
Он предоставляет некоторые статические методы для получения текущих и вызывающих имен классов/методов.
/* 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 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 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 + ")";
}
}
Ответ 11
Чтобы получить имя метода, вызывающего текущий метод, который вы можете использовать:
new Exception("is not thrown").getStackTrace()[1].getMethodName()
Это работает как на моем MacBook, так и на моем Android-телефоне
Я также пробовал:
Thread.currentThread().getStackTrace()[1]
но Android вернет "getStackTrace" Я могу исправить это для Android с помощью
Thread.currentThread().getStackTrace()[2]
но затем я получаю неправильный ответ на своем MacBook
Ответ 12
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
}
}
Ответ 13
Это можно сделать с помощью StackWalker
начиная с 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
спроектирован так, чтобы быть ленивым, поэтому он, вероятно, будет более эффективным, чем, скажем, Thread.getStackTrace
, который охотно создает массив для всего стека вызовов. Также см. JEP для получения дополнительной информации.
Ответ 14
String methodName =Thread.currentThread().getStackTrace()[1].getMethodName();
System.out.println("methodName = " + methodName);
Ответ 15
Альтернативный метод - создать, но не выбросить исключение, и использовать тот объект, из которого можно получить данные трассировки стека, так как метод размещения обычно будет иметь индекс 0 - так долго поскольку JVM хранит эту информацию, как упоминалось выше. Однако это не самый дешевый метод.
От Throwable.getStackTrace() (это было то же самое, что и Java 5):
Нулевой элемент массива (при условии, что длина массива отлична от нуля) представляет верхнюю часть стека, которая является последним вызовом метода в последовательности. Обычно, это та точка, в которой этот throwable был создан и выброшен.
В приведенном ниже фрагменте предполагается, что класс не статический (из-за getClass()), но в стороне.
System.out.printf("Class %s.%s\n", getClass().getName(), new Exception("is not thrown").getStackTrace()[0].getMethodName());
Ответ 16
У меня есть решение, использующее это (в 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())}));
}
}
Ответ 17
Я не знаю, в чем заключается намерение получить текущее имя метода, но если это только для цели отладки, то здесь могут помочь такие фреймворки, как "logback". Например, в logback все, что вам нужно сделать, это использовать шаблон "% M" в конфигурации ведения журнала. Однако это следует использовать с осторожностью, так как это может ухудшить производительность.
Ответ 18
На всякий случай метод, имя которого вы хотите знать, это метод junit test, тогда вы можете использовать правило JNitit TestName: fooobar.com/questions/34876/...
Ответ 19
Я немного переписал ответ Маклеменца:
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);
}
Ответ 20
MethodHandles.lookup().lookupClass().getEnclosingMethod().getName();
Ответ 21
Что не так с этим подходом:
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);
}
}
И прежде чем люди сходят с ума от использования System.out.println(...)
, вы всегда можете и должны создать некоторый метод, чтобы выход можно перенаправить, например:
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());
}
}