Existe-t-il un moyen d'obtenir le nom de la méthode en cours d'exécution en Java?
Existe-t-il un moyen d'obtenir le nom de la méthode en cours d'exécution en Java?
Réponses:
Thread.currentThread().getStackTrace()
contiendra généralement la méthode à partir de laquelle vous l'appelez, mais il y a des pièges (voir Javadoc ):
Certaines machines virtuelles peuvent, dans certaines circonstances, omettre une ou plusieurs trames de pile de la trace de pile. Dans le cas extrême, une machine virtuelle qui n'a aucune information de trace de pile concernant ce thread est autorisée à renvoyer un tableau de longueur nulle à partir de cette méthode.
Techniquement, cela fonctionnera ...
String name = new Object(){}.getClass().getEnclosingMethod().getName();
Cependant, une nouvelle classe interne anonyme sera créée pendant la compilation (par exemple YourClass$1.class
). Cela va donc créer un .class
fichier pour chaque méthode qui déploie cette astuce. De plus, une instance d'objet autrement inutilisée est créée à chaque appel pendant l'exécution. Donc, cela peut être une astuce de débogage acceptable, mais cela s'accompagne d'une surcharge importante.
Un avantage de cette astuce est que les getEncosingMethod()
retours java.lang.reflect.Method
peuvent être utilisés pour récupérer toutes les autres informations de la méthode, y compris les annotations et les noms de paramètres. Cela permet de distinguer des méthodes spécifiques du même nom (surcharge de méthode).
Notez que selon le JavaDoc de getEnclosingMethod()
cette astuce ne devrait pas jeter unSecurityException
car les classes internes doivent être chargées en utilisant le même chargeur de classe. Il n'est donc pas nécessaire de vérifier les conditions d'accès même si un responsable sécurité est présent.
Il est nécessaire d'utiliser getEnclosingConstructor()
pour les constructeurs. Pendant les blocs en dehors des méthodes (nommées), getEnclosingMethod()
retourne null
.
getEnclosingMethod
obtient le nom de la méthode où la classe est définie. this.getClass()
ne vous aidera pas du tout. @wutzebaer pourquoi en auriez-vous même besoin? Vous y avez déjà accès.
Janvier 2009:
Un code complet serait (à utiliser avec la mise en garde de @ Bombe à l'esprit):
/**
* 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
}
Plus dans cette question .
Mise à jour de décembre 2011:
commentaires bleutés :
J'utilise JRE 6 et me donne un nom de méthode incorrect.
Ça marche si j'écrisste[2 + depth].getMethodName().
0
estgetStackTrace()
,1
estgetMethodName(int depth)
et2
appelle la méthode.
virgo47 de réponse (upvoted) calcule effectivement l'index droit d'appliquer afin de récupérer le nom de la méthode.
StackTraceElement
tableau à des fins de débogage et de voir si «principal» est réellement la bonne méthode?
ste[2 + depth].getMethodName()
. 0 est getStackTrace()
, 1 est getMethodName(int depth)
et 2 appelle la méthode. Voir aussi la réponse de @ virgo47 .
Nous avons utilisé ce code pour atténuer la variabilité potentielle de l'index de trace de pile - appelez maintenant 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();
}
}
Semble trop conçu, mais nous avions un certain nombre fixe pour JDK 1.5 et nous avons été un peu surpris que cela ait changé lorsque nous sommes passés à JDK 1.6. Maintenant, c'est la même chose en Java 6/7, mais on ne sait jamais. Ce n'est pas une preuve des changements dans cet index pendant l'exécution - mais j'espère que HotSpot ne fait pas si mal. :-)
public class SomeClass {
public void foo(){
class Local {};
String name = Local.class.getEnclosingMethod().getName();
}
}
nom aura une valeur foo.
null
Ces deux options fonctionnent pour moi avec Java:
new Object(){}.getClass().getEnclosingMethod().getName()
Ou:
Thread.currentThread().getStackTrace()[1].getMethodName()
Le moyen le plus rapide que j'ai trouvé est 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;
}
}
}
Il accède directement à la méthode native getStackTraceElement (int depth). Et stocke la méthode accessible dans une variable statique.
new Throwable().getStackTrace()
pris 5614 ms.
Utilisez le code suivant:
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();
}
Ceci est une extension de la réponse de virgo47 (ci-dessus).
Il fournit des méthodes statiques pour obtenir les noms de classe / méthode actuels et appelants.
/* 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 + ")";
}
}
Pour obtenir le nom de la méthode qui a appelé la méthode actuelle, vous pouvez utiliser:
new Exception("is not thrown").getStackTrace()[1].getMethodName()
Cela fonctionne sur mon MacBook ainsi que sur mon téléphone Android
J'ai aussi essayé:
Thread.currentThread().getStackTrace()[1]
mais Android retournera "getStackTrace". Je pourrais résoudre ce problème pour Android avec
Thread.currentThread().getStackTrace()[2]
mais je reçois la mauvaise réponse sur mon MacBook
getStackTrace()[0]
plutôt que 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];
travaux; e.getClassName();
retourne le nom complet de la classe et e.getMethodName()
retourne le nom du méthon.
getStackTrace()[2]
est faux, cela doit être getStackTrace()[3]
dû au fait que: [0] dalvik.system.VMStack.getThreadStackTrace [1] java.lang.Thread.getStackTrace [2] Utils.getCurrentClassAndMethodNames [3] La fonction a () l'appelant
Cela peut être fait en utilisant StackWalker
depuis 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 conçu pour être paresseux, il est donc probablement plus efficace que, par exemple, Thread.getStackTrace
qui crée avec impatience un tableau pour l'ensemble de la pile d'appels. Consultez également le JEP pour plus d'informations.
Une autre méthode consiste à créer, mais pas à lever, une exception et à utiliser cet objet à partir duquel obtenir les données de trace de pile, car la méthode englobante sera généralement à l'index 0 - tant que la JVM stocke ces informations, comme d'autres l'ont fait. mentionné ci-dessus. Ce n'est cependant pas la méthode la moins chère.
De Throwable.getStackTrace () (c'est la même chose depuis Java 5 au moins):
L'élément zéro du tableau (en supposant que la longueur du tableau est non nulle) représente le haut de la pile, qui est la dernière invocation de méthode dans la séquence. En règle générale , c'est le point auquel ce jetable a été créé et lancé.
L'extrait ci-dessous suppose que la classe n'est pas statique (à cause de getClass ()), mais c'est un aparté.
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);
J'ai une solution en utilisant cela (dans 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())}));
}
}
Je ne sais pas quelle est l'intention derrière l'obtention du nom de la méthode actuellement exécutée, mais si c'est juste à des fins de débogage, les cadres de journalisation comme "logback" peuvent aider ici. Par exemple, lors de la déconnexion, tout ce que vous devez faire est d' utiliser le modèle "% M" dans votre configuration de journalisation . Cependant, cela doit être utilisé avec prudence car cela peut dégrader les performances.
Juste au cas où la méthode dont vous voulez connaître le nom est une méthode de test junit, vous pouvez utiliser la règle junit TestName: https://stackoverflow.com/a/1426730/3076107
La plupart des réponses ici semblent fausses.
public static String getCurrentMethod() {
return getCurrentMethod(1);
}
public static String getCurrentMethod(int skip) {
return Thread.currentThread().getStackTrace()[1 + 1 + skip].getMethodName();
}
Exemple:
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) );
}
Les sorties:
aaa -> aaa
aaa -> aaa
main -> main
J'ai réécrit un peu la réponse du 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()
lance un NullPointerException
pour moi dans Java 7.
Quel est le problème avec cette approche:
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);
}
}
Et avant que les gens ne deviennent fous de l'utilisation, System.out.println(...)
vous pouvez toujours, et devriez, créer une méthode pour que la sortie puisse être redirigée, par exemple:
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());
}
}