Existe-t-il un moyen d'obtenir le nom de la méthode en cours d'exécution en Java ?
Veuillez indiquer si cela est supporté par toutes les JVM et s'il n'existe pas de limitation similaire à l'omission du Stacktrace.
Existe-t-il un moyen d'obtenir le nom de la méthode en cours d'exécution en Java ?
Techniquement, ça va marcher...
String name = new Object(){}.getClass().getEnclosingMethod().getName();
Cependant, une nouvelle classe interne anonyme sera créée au moment de la compilation (par exemple YourClass$1.class
). Cela créera donc un .class
pour chaque méthode qui déploie cette astuce. De plus, une instance d'objet inutilisée est créée à chaque invocation pendant l'exécution. Il s'agit donc d'une astuce de débogage acceptable, mais elle s'accompagne d'une surcharge importante.
L'avantage de cette astuce est que getEnclosingMethod()
renvoie à java.lang.reflect.Method
qui peut être utilisé pour récupérer toutes les autres informations de la méthode, y compris les annotations et les noms des paramètres. Cela permet de distinguer des méthodes spécifiques portant le même nom (surcharge de méthode).
Notez que selon la JavaDoc de getEnclosingMethod()
cette astuce ne devrait pas déclencher un SecurityException
car les classes internes doivent être chargées à l'aide du même chargeur de classes. Il n'est donc pas nécessaire de vérifier les conditions d'accès même si un gestionnaire de sécurité est présent.
Veuillez noter que : Il est nécessaire d'utiliser getEnclosingConstructor()
pour les constructeurs. Pendant les blocs en dehors des méthodes (nommées), getEnclosingMethod()
renvoie à null
.
Veuillez indiquer si cela est supporté par toutes les JVM et s'il n'existe pas de limitation similaire à l'omission du Stacktrace.
Cela ne vous donnera pas la méthode d'exécution actuelle. Cela vous donnera la méthode dans laquelle une classe anonyme/locale est définie. - [docs.oracle.com/javase/6/docs/api/java/lang/](http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getEnclosingMethod())
[Thread](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Thread.html).[currentThread()](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Thread.html#currentThread()).[getStackTrace()](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Thread.html#getStackTrace())
contiendra généralement la méthode à partir de laquelle vous l'appelez, mais il existe des pièges (cf. [Javadoc](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Thread.html#getStackTrace()) ) :
Certaines machines virtuelles peuvent, dans certaines circonstances, omettre une ou plusieurs trames de pile de la trace de la pile. Dans le cas extrême, une machine virtuelle qui ne dispose d'aucune information de suivi de pile concernant ce thread est autorisée à renvoyer un tableau de longueur nulle à partir de cette méthode.
Oui, c'est ça. La documentation pour Jetable . [getStackTrace()]( download.oracle.com/javase/1.5.0/docs/api/java/lang/ contient exactement le même paragraphe.
La chose sous-jacente est que la JVM n'est pas requis de pouvoir fournir une trace de pile, mais que beaucoup de travail a été fait pour rendre HotSpot très fiable. Vous devez cependant le savoir, au cas où vous voudriez que votre code ne dépende pas du comportement d'une JVM spécifique.
Janvier 2009 :
Un code complet serait (à utiliser avec L'avertissement 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
}
En savoir plus cette question .
Mise à jour de décembre 2011 :
bleuâtre commentaires :
J'utilise JRE 6 et me donne un nom de méthode incorrect.
Cela fonctionne si j'écrisste[2 + depth].getMethodName().
0
estgetStackTrace()
,1
estgetMethodName(int depth)
et2
est la méthode d'invocation.
Vierge47 's réponse (upvoted) calcule en fait le bon index à appliquer afin de récupérer le nom de la méthode.
@Amigable : avez vous essayé d'imprimer le tout StackTraceElement
à des fins de débogage et pour voir si 'main' est la bonne méthode ?
J'utilise JRE 6 et me donne un nom de méthode incorrect. Cela fonctionne si j'écris ste[2 + depth].getMethodName()
. 0 est getStackTrace()
, 1 est getMethodName(int depth)
et 2 est la méthode d'invocation. Voir aussi La réponse de @virgo47 .
Nous avons utilisé ce code pour atténuer la variabilité potentielle de l'indice de la trace de la pile - maintenant, il suffit d'appeler 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();
}
}
Cela semble excessif, mais nous avions un nombre fixe pour le JDK 1.5 et nous avons été un peu surpris qu'il change lorsque nous sommes passés au JDK 1.6. Maintenant, c'est le même dans Java 6/7, mais on ne sait jamais. Il n'est pas à l'épreuve des changements dans cet indice pendant l'exécution - mais espérons que HotSpot ne fait pas si mal :-)
Cela reste subtilement dépendant du fournisseur. La JVM n'est pas tenue de fournir des données fiables pour ce code.
Selon les spécifications de la JVM, la JVM n'est pas tenue de fournir des traces complètes de la pile (optimisation, inlining, etc.) et vous avez déjà découvert que votre heuristique a changé entre Oracle Java 5 et Oracle Java 6. Rien ne garantit qu'une autre JVM se comportera comme vous l'attendez dans votre code, vous vous fiez donc subtilement au comportement spécifique du fournisseur. Ce qui est parfaitement acceptable, tant que vous en êtes conscient, mais si - par exemple - vous devez déployer sur une JVM IBM (ce que nous devons faire) ou sur une instance Zing, vous devrez peut-être revoir votre heuristique.
@eigil c'est intéressant mais sans plus d'informations, il est difficile de dire ce qui a "mal tourné" ou quand nous devrions nous attendre à ce qu'il en soit ainsi. null
Il s'agit de la même astuce que cette réponse . Elle a l'avantage de ne pas créer d'instance d'objet parasite, mais elle a l'inconvénient de nécessiter une déclaration de classe qui ne peut pas être inlined dans la déclaration (c'est-à-dire qu'elle nécessite normalement une ligne de code supplémentaire).
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.