20 ответов:
Thread.currentThread().getStackTrace()обычно содержит метод, из которого вы его вызываете, но есть подводные камни (см. документация):некоторые виртуальные машины могут при некоторых обстоятельствах пропустить один или несколько кадров стека из трассировки стека. В крайнем случае виртуальная машина, которая не имеет информации трассировки стека, относящейся к этому потоку, может возвращать массив нулевой длины из этого метода.
технически это будет работать...
String name = new Object(){}.getClass().getEnclosingMethod().getName();однако во время компиляции будет создан новый анонимный внутренний класс (например,
YourClass.class). Так что это создаст для каждого метода, который развертывает этот трюк. Кроме того, в противном случае неиспользуемый экземпляр объекта создается при каждом вызове во время выполнения. Таким образом, это может быть приемлемый трюк отладки, но он имеет значительные накладные расходы.преимущество этого трюка в том, что
getEncosingMethod()возвращаетjava.lang.reflect.Methodкоторый может быть использован для получения всех других методов, включая аннотации и имена параметров. Это позволяет различать конкретные методы с одинаковым именем (перегрузка метода).обратите внимание, что в соответствии с JavaDoc из
getEnclosingMethod()этот трюк не должен бросатьSecurityExceptionкак внутренние классы должны быть загружены с помощью того же загрузчика классов. Поэтому нет необходимости проверять условия доступа, даже если присутствует менеджер безопасности.это требуется использовать
getEnclosingConstructor()для конструкторов. Во время блоков вне (именованных) методов,getEnclosingMethod()возвращаетnull.
январь 2009:
Полный код будет (использовать с @машина это!--10--> в виду):/** * 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:
иссиня комментарии:
Я использую JRE 6 и дает мне неправильное имя метода.
Это работает, если я пишуste[2 + depth].getMethodName().
0иgetStackTrace(),1иgetMethodName(int depth)и2вызывает метод.virgo47 ' s ответ (upvoted) фактически вычисляет правильный индекс для применения, чтобы вернуть имя метода.
мы использовали этот код для смягчения потенциальной изменчивости индекса трассировки стека-теперь просто вызовите 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(); } }Кажется сверхинженерным, но у нас был некоторый фиксированный номер для JDK 1.5 и были немного удивлены, что он изменился, когда мы перешли на JDK 1.6. Теперь то же самое в Java 6/7, но вы просто не знаете. Это не доказательство изменений в этом индексе во время выполнения - но, надеюсь, HotSpot не делает этого плохо. : -)
public class SomeClass { public void foo(){ class Local {}; String name = Local.class.getEnclosingMethod().getName(); } }имя будет иметь значение foo.
самый быстрый способ Я нашел это:
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). И сохраняет доступный метод в статической переменной.
использовать следующий код :
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace(); StackTraceElement e = stacktrace[1];//coz 0th will be getStackTrace so 1st String methodName = e.getMethodName(); System.out.println(methodName);
оба этих параметра работают для меня с Java:
new Object(){}.getClass().getEnclosingMethod().getName()или:
Thread.currentThread().getStackTrace()[1].getMethodName()
public static String getCurrentMethodName() { return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName(); }
Это расширение 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'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 + ")"; } }
получить имя метода, который вызвал текущий метод вы можете использовать:
new Exception("is not thrown").getStackTrace()[1].getMethodName()это работает на моем MacBook, а также на моем телефоне Android
Я тоже пробовал:
Thread.currentThread().getStackTrace()[1]но Android вернет " getStackTrace" Я мог бы исправить это для Android с
Thread.currentThread().getStackTrace()[2]но тогда я получаю неправильный ответ на моем 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 } }
альтернативным методом является создание, но не выбрасывание исключения и использование этого объекта для получения данных трассировки стека, так как метод enclosing будет обычно быть в индексе 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());
String methodName =Thread.currentThread().getStackTrace()[1].getMethodName(); System.out.println("methodName = " + methodName);
Я не знаю, в чем заключается намерение получить имя текущего выполняемого метода, но если это только для отладки, то здесь могут помочь фреймворки ведения журнала, такие как "logback". Например, в logback, все, что вам нужно сделать, это используйте шаблон "%M " в конфигурации ведения журнала. Однако это следует использовать с осторожностью, так как это может ухудшить производительность.
У меня есть решение, используя это (в 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())})); } }
на всякий случай метод, имя которого вы хотите знать, является методом тестирования junit, тогда вы можете использовать правило junit TestName:https://stackoverflow.com/a/1426730/3076107
Это можно сделать с помощью
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 для получения дополнительной информации.
что не так с этим подходом:
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()); } }
Comments