Obtendo o nome do método atualmente em execução

Existe uma maneira de obter o nome do método atualmente em execução em Java?

Thread . currentThread() . getStackTrace() normalmente contém o método do qual você está chamando, mas há armadilhas (veja Javadoc ):

Algumas máquinas virtuais podem, em algumas circunstâncias, omitir um ou mais frameworks de pilha do rastreamento de pilha. No caso extremo, uma máquina virtual que não possui informações de rastreamento de pilha referentes a esse encadeamento pode retornar um array de comprimento zero desse método.

Tecnicamente isso vai funcionar …

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

No entanto, uma nova class interna anônima será criada durante o tempo de compilation (por exemplo, YourClass$1.class ). Portanto, isso criará um arquivo .class para cada método que implemente esse truque. Além disso, uma instância de object de outra forma não utilizada é criada em cada chamada durante o tempo de execução. Então, isso pode ser um truque de debugging aceitável, mas vem com uma sobrecarga significativa.

Uma vantagem desse truque é que getEncosingMethod() retorna java.lang.reflect.Method que pode ser usado para recuperar todas as outras informações do método, incluindo annotations e nomes de parâmetros. Isto torna possível distinguir entre methods específicos com o mesmo nome (sobrecarga de método).

Observe que, de acordo com o JavaDoc de getEnclosingMethod() esse truque não deve lançar uma SecurityException pois as classs internas devem ser carregadas usando o mesmo carregador de classs. Portanto, não há necessidade de verificar as condições de access, mesmo se houver um gerente de segurança presente.

É necessário usar getEnclosingConstructor() para construtores. Durante os blocos fora dos methods (named), getEnclosingMethod() retorna null .

Janeiro de 2009:
Um código completo seria (para usar com a advertência do @ Bombe em mente):

 /** * 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 }

Mais nesta questão .

Atualização de dezembro de 2011:

comentários azulados :

Eu uso o JRE 6 e me dá um nome de método incorreto.
Funciona se eu escrever ste[2 + depth].getMethodName().

  • 0 é getStackTrace() ,
  • 1 é getMethodName(int depth) e
  • 2 está invocando o método.

A resposta de virgo47 (upvoted) na verdade calcula o índice correto a ser aplicado para recuperar o nome do método.

Usamos esse código para atenuar a variabilidade potencial no índice de rastreio de pilha. Agora, basta chamar o utilitário methodName:

 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 overengineered, mas nós tivemos algum número fixo para JDK 1.5 e estávamos um pouco surpresos que mudou quando nós nos mudamos para JDK 1.6. Agora é o mesmo no Java 6/7, mas você nunca sabe. Não é a prova de alterações nesse índice durante o tempo de execução – mas esperamos que o HotSpot não seja tão ruim assim. 🙂

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

name terá valor foo.

O caminho mais rápido que encontrei é o seguinte:

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

Ele acessa o método nativo getStackTraceElement (int depth) diretamente. E armazena o método acessível em uma variável estática.

Use o seguinte 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 as opções funcionam para mim com o Java:

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

Ou:

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

Esta é uma expansão da resposta do virgo47 (acima).

Ele fornece alguns methods estáticos para obter os nomes de classs / methods atuais e chamadores.

 /* 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 obter o nome do método que chamou o método atual, você pode usar:

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

Isso funciona no meu MacBook, bem como no meu telefone Android

Eu também tentei:

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

mas o Android vai retornar “getStackTrace” eu poderia consertar isso para Android com

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

mas depois recebo a resposta errada no meu 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 } } 

Um método alternativo é criar, mas não lançar, uma Exceção e usar esse object a partir do qual obter os dados de rastreamento de pilha, pois o método de inclusão normalmente estará no índice 0 – contanto que a JVM armazene essas informações, como outras Mencionado acima. Este não é o método mais barato, no entanto.

De Throwable.getStackTrace () (isto tem sido o mesmo desde o Java 5 pelo menos):

O elemento zeroth da matriz (assumindo que o comprimento da matriz é diferente de zero) representa o topo da pilha, que é a última invocação do método na sequência. Normalmente , este é o ponto em que este lance foi criado e lançado.

O trecho abaixo presume que a class é não-estática (por causa de getClass ()), mas isso é um 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); 

Eu não sei qual é a intenção por trás de obter o nome do método atualmente executado, mas se isso é apenas para fins de debugging, então, o registro de estruturas como “logback” pode ajudar aqui. Por exemplo, no logback, tudo o que você precisa fazer é usar o padrão “% M” em sua configuração de criação de log . No entanto, isso deve ser usado com cuidado, pois isso pode prejudicar o desempenho.

Eu tenho solução usando isso (no 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(); 

Apenas no caso de o método cujo nome você deseja conhecer seja um método de teste junit, use a regra junit TestName: https://stackoverflow.com/a/1426730/3076107

O que há de errado com essa abordagem:

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

E antes que as pessoas fiquem loucas em usar System.out.println(...) você sempre pode, e deve, criar algum método para que a saída possa ser redirecionada, por exemplo:

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