¿Hay alguna manera de obtener el nombre del método que se está ejecutando actualmente en Java?
¿Hay alguna manera de obtener el nombre del método que se está ejecutando actualmente en Java?
Respuestas:
Thread.currentThread().getStackTrace()
generalmente contendrá el método desde el que lo está llamando, pero existen dificultades (consulte Javadoc ):
Algunas máquinas virtuales pueden, en algunas circunstancias, omitir uno o más marcos de pila de la traza de pila. En el caso extremo, una máquina virtual que no tiene información de seguimiento de pila relacionada con este subproceso puede devolver una matriz de longitud cero de 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 compilación (por ejemplo YourClass$1.class
). Entonces esto creará un .class
archivo para cada método que despliegue este truco. Además, se crea una instancia de objeto no utilizada en cada invocación durante el tiempo de ejecución. Por lo tanto, este puede ser un truco de depuración aceptable, pero viene con una sobrecarga significativa.
Una ventaja de este truco es que los getEncosingMethod()
retornos java.lang.reflect.Method
se pueden usar para recuperar toda la otra 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étodos).
Tenga en cuenta que de acuerdo con el JavaDoc de getEnclosingMethod()
este truco no se debe lanzar un SecurityException
ya que las clases internas deben 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 su uso getEnclosingConstructor()
para constructores. Durante los bloques fuera de los métodos (con nombre), getEnclosingMethod()
regresa null
.
getEnclosingMethod
obtiene el nombre del método donde se define la clase. this.getClass()
no te ayudará en absoluto. @wutzebaer, ¿por qué lo necesitarías? Ya tienes acceso a ellos.
Enero de 2009:
un código completo sería (para usar con la advertencia de @Bombe en mente):
/**
* 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
}
Más en esta pregunta .
Actualización de diciembre de 2011:
comentarios azulados :
Yo uso JRE 6 y me da un nombre de método incorrecto.
Funciona si escriboste[2 + depth].getMethodName().
0
esgetStackTrace()
,1
esgetMethodName(int depth)
y2
Es un método de invocación.
virgo47 's respuesta (upvoted) en realidad calcula el índice derecho de aplicar con el fin de recuperar el nombre del método.
StackTraceElement
arreglo para propósitos de depuración y ver si 'main' es realmente el método correcto?
ste[2 + depth].getMethodName()
. 0 es getStackTrace()
, 1 es getMethodName(int depth)
y 2 es un método de invocación. Ver también la respuesta de @ virgo47 .
Utilizamos este código para mitigar la variabilidad potencial en el índice de seguimiento de la pila; 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 un exceso de ingeniería, pero teníamos un número fijo para JDK 1.5 y nos sorprendió un poco que cambiara cuando nos mudamos 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 espero 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.
null
Ambas opciones me funcionan con Java:
new Object(){}.getClass().getEnclosingMethod().getName()
O:
Thread.currentThread().getStackTrace()[1].getMethodName()
La forma 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 profundidad). Y almacena el Método accesible en una variable estática.
new Throwable().getStackTrace()
tomó 5614ms.
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);
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 invocadores.
/* Utility class: Getting the name of the current executing method
* /programming/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. /programming/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 en mi MacBook y 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
getStackTrace()[0]
lugar de getStackTrace()[1]
. YMMV.
Thread.currentThread().getStackTrace()[2]
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
}
}
final StackTraceElement e = Thread.currentThread().getStackTrace()[2];
trabajos; e.getClassName();
devolver el nombre completo de la clase y e.getMethodName()
devolver el nombre del methon.
getStackTrace()[2]
está mal, tiene que ser getStackTrace()[3]
porque: [0] dalvik.system.VMStack.getThreadStackTrace [1] java.lang.Thread.getStackTrace [2] Utils.getCurrentClassAndMethodNames [3] La función a () llamando a este
Esto se puede hacer StackWalker
desde 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
está diseñado para ser perezoso, por lo que es probable que sea más eficiente que, por ejemplo, Thread.getStackTrace
que crea ansiosamente una matriz para toda la pila de llamadas. También vea el JEP para más información.
Un método alternativo es crear, pero no lanzar, una Excepción, y usar ese objeto desde el cual obtener los datos de seguimiento de la pila, ya que el método de inclusión generalmente estará en el índice 0, siempre que la JVM almacene esa información, como lo han hecho otros. mencionado anteriormente. Sin embargo, este no es el método más barato.
Desde Throwable.getStackTrace () (esto ha sido lo mismo desde Java 5 al menos):
El elemento cero de la matriz (suponiendo que la longitud de la matriz no es cero) representa la parte superior de la pila, que es la última invocación de método en la secuencia. Por lo general , este es el punto en el que este lanzamiento se creó y se lanzó.
El fragmento a continuación asume que la clase no es estática (debido a getClass ()), pero eso es un aparte.
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);
Tengo una solución usando esto (en 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())}));
}
}
No sé cuál es la intención detrás de obtener el nombre del método ejecutado actualmente, pero si eso es solo para fines de depuración, entonces los marcos de registro como "logback" pueden ayudar aquí. Por ejemplo, en el inicio de sesión, 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.
En caso de que el método cuyo nombre desea saber sea un método de prueba junit, puede usar la regla Junit TestName: https://stackoverflow.com/a/1426730/3076107
La mayoría de las respuestas aquí parecen incorrectas.
public static String getCurrentMethod() {
return getCurrentMethod(1);
}
public static String getCurrentMethod(int skip) {
return Thread.currentThread().getStackTrace()[1 + 1 + skip].getMethodName();
}
Ejemplo:
public static void main(String[] args) {
aaa();
}
public static void aaa() {
System.out.println("aaa -> " + getCurrentMethod( ) );
System.out.println("aaa -> " + getCurrentMethod(0) );
System.out.println("main -> " + getCurrentMethod(1) );
}
Salidas:
aaa -> aaa
aaa -> aaa
main -> main
Reescribí un poco la respuesta de maklemenz :
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);
}
MethodHandles.lookup().lookupClass().getEnclosingMethod().getName();
getEnclosingMethod()
lanza un NullPointerException
para mí en Java 7.
¿Qué tiene de malo 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 la gente se vuelva loca por el uso System.out.println(...)
, siempre podría y debería crear algún método para que la salida se pueda redirigir, 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());
}
}