Ottenere il nome del metodo attualmente in esecuzione

C’è un modo per ottenere il nome del metodo attualmente in esecuzione in Java?

Thread currentThread() . getStackTrace() solito contiene il metodo da cui viene chiamato ma ci sono dei problemi (vedi Javadoc ):

Alcune macchine virtuali possono, in alcune circostanze, omettere uno o più frame dello stack dall’analisi dello stack. Nel caso estremo, una macchina virtuale che non ha informazioni di traccia di stack su questo thread è autorizzata a restituire un array a lunghezza zero da questo metodo.

Tecnicamente funzionerà …

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

Tuttavia, durante la compilazione verrà creata una nuova class interna anonima (ad es. YourClass$1.class ). Quindi questo creerà un file .class per ogni metodo che distribuisce questo trucco. Inoltre, in ogni richiamo durante il runtime viene creata un’istanza dell’object inutilizzata. Quindi questo può essere un trucco di debug accettabile, ma ha un sovraccarico significativo.

Un vantaggio di questo trucco è che getEncosingMethod() restituisce java.lang.reflect.Method che può essere utilizzato per recuperare tutte le altre informazioni del metodo incluse annotazioni e nomi di parametri. Ciò rende ansible distinguere tra metodi specifici con lo stesso nome (overload di metodi).

Si noti che, secondo JavaDoc di getEnclosingMethod() questo trucco non dovrebbe generare SecurityException quanto le classi interne dovrebbero essere caricate usando lo stesso programma di caricamento classi. Quindi non è necessario verificare le condizioni di accesso anche se è presente un gestore della sicurezza.

È necessario utilizzare getEnclosingConstructor() per i costruttori. Durante i blocchi esterni ai metodi (denominati), getEnclosingMethod() restituisce null .

Gennaio 2009:
Un codice completo sarebbe (da usare con l’avvertimento di @ Bombe in 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 }

Altro in questa domanda .

Aggiornamento dicembre 2011:

commenti bluastri :

Io uso JRE 6 e mi dà il nome del metodo errato.
Funziona se scrivo ste[2 + depth].getMethodName().

  • 0 è getStackTrace() ,
  • 1 è getMethodName(int depth) e
  • 2 sta invocando il metodo.

La risposta di virgo47 (upvoted) calcola effettivamente l’indice giusto da applicare per recuperare il nome del metodo.

Abbiamo usato questo codice per mitigare la potenziale variabilità dell’indice di traccia dello stack – ora chiama semplicemente 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(); } } 

Sembra troppo ingegnoso, ma avevamo un numero fisso per JDK 1.5 e siamo rimasti un po ‘sorpresi quando è stato cambiato in JDK 1.6. Ora è lo stesso in Java 6/7, ma non si sa mai. Non è una prova delle modifiche in quell’indice durante il runtime – ma si spera che HotSpot non faccia così male. 🙂

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

il nome avrà valore foo.

Il modo più veloce che ho trovato è che:

 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 direttamente al metodo nativo getStackTraceElement (int depth). E memorizza il metodo accessibile in una variabile statica.

Usa il seguente codice:

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

Entrambe queste opzioni funzionano per me 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(); } 

Questa è un’espansione sulla risposta di virgo47 (sopra).

Fornisce alcuni metodi statici per ottenere i nomi di class / metodo correnti e invocanti.

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

Per ottenere il nome del metodo che ha chiamato il metodo corrente puoi usare:

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

Funziona sul mio MacBook e sul mio telefono Android

Ho anche provato:

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

ma Android restituirà “getStackTrace” che potrei risolvere con Android

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

ma poi ho la risposta sbagliata sul mio 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 metodo alternativo è quello di creare, ma non lanciare, un’eccezione e utilizzare quell’object da cui ottenere i dati di traccia dello stack, poiché il metodo di inclusione sarà tipicamente all’indice 0 – purché la JVM memorizzi tali informazioni, come altri hanno menzionato sopra. Questo non è il metodo più economico, tuttavia.

Da Throwable.getStackTrace () (questo è stato lo stesso da almeno Java 5):

L’elemento zeroth dell’array (supponendo che la lunghezza dell’array sia diverso da zero) rappresenta la parte superiore dello stack, che è l’ultima chiamata di metodo nella sequenza. In genere , questo è il punto in cui questo throwable è stato creato e lanciato.

Lo snippet seguente presuppone che la class non sia statica (a causa di getClass ()), ma questa è una parte.

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

Non so quale sia l’intenzione di ottenere il nome del metodo attualmente eseguito, ma se questo è solo per scopi di debug, allora il logging di framework come “logback” può aiutare qui. Ad esempio, nel logback, tutto ciò che devi fare è usare il pattern “% M” nella tua configurazione di logging . Tuttavia, questo dovrebbe essere usato con caucanvas in quanto ciò potrebbe peggiorare le prestazioni.

Ho una soluzione usando questo (in 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(); 

Nel caso in cui il metodo che si desidera conoscere sia un metodo di test di junit, è ansible utilizzare la regola TestName di junit: https://stackoverflow.com/a/1426730/3076107

Cosa c’è di sbagliato in questo approccio:

 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 prima che la gente impazzisca nell’usare System.out.println(...) si può sempre e dovrebbe creare un metodo per redirect l’output, ad esempio:

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