Existe uma maneira de obter o nome do método atualmente em execução em Java?
Existe uma maneira de obter o nome do método atualmente em execução em Java?
Respostas:
Thread.currentThread().getStackTrace()
normalmente conterá o método do qual você está chamando, mas existem armadilhas (consulte Javadoc ):
Algumas máquinas virtuais podem, em algumas circunstâncias, omitir um ou mais quadros de pilha do rastreamento de pilha. No caso extremo, uma máquina virtual que não possui informações de rastreamento de pilha relacionadas a esse encadeamento tem permissão para retornar uma matriz de comprimento zero desse método.
Tecnicamente isso vai funcionar ...
String name = new Object(){}.getClass().getEnclosingMethod().getName();
No entanto, uma nova classe interna anônima será criada durante o tempo de compilação (por exemplo YourClass$1.class
). Portanto, isso criará um .class
arquivo para cada método que implanta esse truque. Além disso, uma instância de objeto não utilizada é criada em cada chamada durante o tempo de execução. Portanto, esse pode ser um truque de depuração aceitável, mas ele vem com uma sobrecarga significativa.
Uma vantagem desse truque é que getEncosingMethod()
retornos java.lang.reflect.Method
podem ser usados para recuperar todas as outras informações do método, incluindo anotações e nomes de parâmetros. Isso torna possível distinguir entre métodos específicos com o mesmo nome (sobrecarga de método).
Observe que, de acordo com o JavaDoc getEnclosingMethod()
deste truque, não deve ser lançado SecurityException
como as classes internas devem ser carregadas usando o mesmo carregador de classes. Portanto, não há necessidade de verificar as condições de acesso, mesmo se um gerente de segurança estiver presente.
É necessário usar getEnclosingConstructor()
para construtores. Durante os blocos fora dos métodos (nomeados), getEnclosingMethod()
retorna null
.
getEnclosingMethod
obtém o nome do método em que a classe está definida. this.getClass()
não vai te ajudar em nada. @wutzebaer Por que você precisaria? Você já tem acesso a eles.
Janeiro de 2009:
Um código completo seria (para usar com a advertência de @ Bombe ):
/**
* 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
}
Mais nesta pergunta .
Atualização em dezembro de 2011:
comentários azulados :
Eu uso o JRE 6 e me fornece o nome do método incorreto.
Funciona se eu escreverste[2 + depth].getMethodName().
0
égetStackTrace()
,1
égetMethodName(int depth)
e2
está invocando método.
virgo47 's resposta (upvoted) realmente calcula o índice direito de aplicar a fim de obter de volta o nome do método.
StackTraceElement
matriz para fins de depuração e ver se 'main' é realmente o método certo?
ste[2 + depth].getMethodName()
. 0 é getStackTrace()
, 1 é getMethodName(int depth)
e 2 está chamando o método. Veja também a resposta de @ virgo47 .
Usamos esse código para reduzir a variabilidade potencial no índice de rastreamento de pilha - agora basta chamar 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 ser superengenharia, mas tínhamos um número fixo para o JDK 1.5 e ficamos um pouco surpresos ao mudar quando mudamos para o JDK 1.6. Agora é o mesmo no Java 6/7, mas você nunca sabe. Não é prova de alterações nesse índice durante o tempo de execução - mas espero que o HotSpot não seja tão ruim assim. :-)
public class SomeClass {
public void foo(){
class Local {};
String name = Local.class.getEnclosingMethod().getName();
}
}
nome terá valor foo.
null
Ambas as opções funcionam para mim com Java:
new Object(){}.getClass().getEnclosingMethod().getName()
Ou:
Thread.currentThread().getStackTrace()[1].getMethodName()
A maneira mais rápida que encontrei é:
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.
new Throwable().getStackTrace()
levou 5614ms.
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);
public static String getCurrentMethodName() {
return Thread.currentThread().getStackTrace()[2].getClassName() + "." + Thread.currentThread().getStackTrace()[2].getMethodName();
}
Esta é uma expansão da resposta de virgo47 (acima).
Ele fornece alguns métodos estáticos para obter os nomes de classe / método atuais 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 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 e no meu telefone Android
Eu também tentei:
Thread.currentThread().getStackTrace()[1]
mas o Android retornará "getStackTrace". Eu poderia corrigir isso no Android com
Thread.currentThread().getStackTrace()[2]
mas então eu recebo a resposta errada no meu MacBook
getStackTrace()[0]
, em vez 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];
trabalho; e.getClassName();
retorne o nome completo da classe e e.getMethodName()
retorne o nome methon.
getStackTrace()[2]
está errado, deve ser getStackTrace()[3]
porque: [0] dalvik.system.VMStack.getThreadStackTrace [1] java.lang.Thread.getStackTrace [2] Utils.getCurrentClassAndMethodNames [3] A função a () chamando este
Isso pode ser feito usando o 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
foi projetado para ser preguiçoso, então é provável que seja mais eficiente do que, digamos, o Thread.getStackTrace
que cria ansiosamente uma matriz para todo o callstack. Veja também o JEP para mais informações.
Um método alternativo é criar, mas não lançar, uma exceção e usar esse objeto do qual obter os dados de rastreamento de pilha, pois o método envolvente estará normalmente no índice 0 - desde que a JVM armazene essas informações, como outros Mencionado acima. Este não é o método mais barato, no entanto.
De Throwable.getStackTrace () (isso é 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 esse lançamento foi criado e lançado.
O snippet abaixo assume que a classe 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 tenho solução usando isso (no 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())}));
}
}
Não sei qual é a intenção por trás do nome do método atualmente executado, mas se isso for apenas para fins de depuração, as estruturas de log como "logback" podem ajudar aqui. Por exemplo, no logback, tudo que você precisa fazer é usar o padrão "% M" na sua configuração de log . No entanto, isso deve ser usado com cuidado, pois isso pode prejudicar o desempenho.
Caso o método que você deseja saber seja um método de teste de junit, você poderá usar a regra TestName de junit: https://stackoverflow.com/a/1426730/3076107
A maioria das respostas aqui parece errada.
public static String getCurrentMethod() {
return getCurrentMethod(1);
}
public static String getCurrentMethod(int skip) {
return Thread.currentThread().getStackTrace()[1 + 1 + skip].getMethodName();
}
Exemplo:
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) );
}
Saídas:
aaa -> aaa
aaa -> aaa
main -> main
Reescrevi um pouco a resposta do 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()
lança um NullPointerException
para mim em Java 7.
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 por 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());
}
}