Obteniendo el nombre del método actualmente en ejecución

¿Hay alguna manera de obtener el nombre del método que se está ejecutando actualmente en Java?

Thread . currentThread() . getStackTrace() generalmente contendrá el método desde el que lo llama, pero hay dificultades (vea Javadoc ):

Algunas máquinas virtuales pueden, en algunas circunstancias, omitir uno o más marcos de stack del rastro de la stack. En el caso extremo, una máquina virtual que no tiene información de rastreo de stack con respecto a este subproceso puede devolver un conjunto de longitud cero desde este método.

Técnicamente esto funcionará …

 String name = new Object(){}.getClass().getEnclosingMethod().getName(); 

Sin embargo, se creará una nueva clase interna anónima durante el tiempo de comstackción (p YourClass$1.class Ej. YourClass$1.class ). Así que esto creará un archivo .class para cada método que implementa este truco. Además, se crea una instancia de objeto no utilizada en cada invocación durante el tiempo de ejecución. Así que esto puede ser un truco de depuración aceptable, pero viene con una sobrecarga significativa.

Una ventaja de este truco es que getEncosingMethod() devuelve java.lang.reflect.Method que se puede usar para recuperar toda la demás información del método, incluidas las anotaciones y los nombres de los parámetros. Esto permite distinguir entre métodos específicos con el mismo nombre (sobrecarga de método).

Tenga en cuenta que de acuerdo con getEnclosingMethod() de getEnclosingMethod() este truco no debería arrojar una SecurityException ya que las clases internas deberían cargarse utilizando el mismo cargador de clases. Por lo tanto, no es necesario verificar las condiciones de acceso, incluso si hay un administrador de seguridad presente.

Se requiere usar getEnclosingConstructor() para constructores. Durante los bloques fuera de los métodos (nombrados), getEnclosingMethod() devuelve null .

Enero de 2009:
Un código completo sería (para usar con la advertencia de @ Bombe ):

 /** * Get the method name for a depth in call stack. 
* 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 }

Más en esta pregunta .

Actualización de diciembre de 2011:

comentarios azulados :

Uso JRE 6 y me da un nombre de método incorrecto.
Funciona si escribo ste[2 + depth].getMethodName().

  • 0 es getStackTrace() ,
  • 1 es getMethodName(int depth) y
  • 2 es el método de invocación.

La respuesta de virgo47 (votada) en realidad calcula el índice correcto para aplicar a fin de recuperar el nombre del método.

Usamos este código para mitigar la variabilidad potencial en el índice de seguimiento de stack; ahora solo llame a 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(); } } 

Parece demasiado ingenioso, pero teníamos un número fijo para JDK 1.5 y nos sorprendió un poco que cambiara cuando pasamos a JDK 1.6. Ahora es lo mismo en Java 6/7, pero nunca se sabe. No es una prueba de los cambios en ese índice durante el tiempo de ejecución, pero es de esperar que HotSpot no lo haga tan mal. 🙂

  public class SomeClass { public void foo(){ class Local {}; String name = Local.class.getEnclosingMethod().getName(); } } 

nombre tendrá valor foo.

La manera más rápida que encontré es que:

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

Accede directamente al método nativo getStackTraceElement (int depth). Y almacena el Método accesible en una variable estática.

Use el siguiente código:

  StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace(); StackTraceElement e = stacktrace[1];//coz 0th will be getStackTrace so 1st String methodName = e.getMethodName(); System.out.println(methodName); 

Ambas opciones funcionan para mí con Java:

 new Object(){}.getClass().getEnclosingMethod().getName() 

O:

 Thread.currentThread().getStackTrace()[1].getMethodName() 
 public static String getCurrentMethodName() { return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName(); } 

Esta es una expansión de la respuesta de virgo47 (arriba).

Proporciona algunos métodos estáticos para obtener los nombres de clase / método actuales e invocados.

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

Para obtener el nombre del método que llamó al método actual, puede usar:

 new Exception("is not thrown").getStackTrace()[1].getMethodName() 

Esto funciona tanto en mi MacBook como en mi teléfono Android

También probé:

 Thread.currentThread().getStackTrace()[1] 

pero Android devolverá “getStackTrace” Podría arreglar esto para Android con

 Thread.currentThread().getStackTrace()[2] 

pero luego recibo la respuesta incorrecta en mi 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 } } 

Un método alternativo es crear, pero no lanzar, una excepción y usar ese objeto para obtener los datos de seguimiento de la stack, ya que el método de inclusión generalmente estará en el índice 0, siempre que la JVM almacene esa información, ya que otros tienen mencionado anteriormente. Este no es el método más barato, sin embargo.

De Throwable.getStackTrace () (esto ha sido el mismo desde Java 5 al menos):

El elemento zeroth de la matriz (suponiendo que la longitud de la matriz no es cero) representa la parte superior de la stack, que es la última invocación de método en la secuencia. Típicamente , este es el punto en el cual este throwable fue creado y lanzado.

El siguiente fragmento asume que la clase no es estática (debido a getClass ()), pero eso es un lado.

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

No sé cuál es la intención detrás de obtener el nombre del método ejecutado actualmente, pero si eso es sólo para fines de depuración, el registro de marcos como “logback” puede ayudar aquí. Por ejemplo, en logback, todo lo que necesita hacer es usar el patrón “% M” en su configuración de registro . Sin embargo, esto debe usarse con precaución, ya que puede degradar el rendimiento.

Tengo una solución que usa esto (en Android)

 /** * @param className fully qualified className * 
*
YourClassName.class.getName(); *

* @param classSimpleName simpleClassName *
* YourClassName.class.getSimpleName(); *

*/ 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())})); } }
 MethodHandles.lookup().lookupClass().getEnclosingMethod().getName(); 

En caso de que el método cuyo nombre desea conocer sea un método de prueba junit, entonces puede usar la regla junit TestName: https://stackoverflow.com/a/1426730/3076107

¿Qué pasa con este enfoque?

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

Y antes de que las personas se vuelvan locas por usar System.out.println(...) siempre podrías, y deberías, crear algún método para que la salida pueda redirigirse, por ejemplo:

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