499 votes

Obtenir le nom de la méthode en cours d'exécution

Existe-t-il un moyen d'obtenir le nom de la méthode en cours d'exécution en Java ?

339voto

Devin Points 591

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 .

0 votes

Veuillez indiquer si cela est supporté par toutes les JVM et s'il n'existe pas de limitation similaire à l'omission du Stacktrace.

9 votes

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

7 votes

Class Local {} ; String name = Local.class.getEnclosingMethod().getName() ;

188voto

Bombe Points 34185

[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.

7 votes

Ce même écueil est-il vrai pour les traces de pile dans les exceptions ?

8 votes

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.

4 votes

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.

138voto

VonC Points 414372

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'écris ste[2 + depth].getMethodName().

  • 0 est getStackTrace() ,
  • 1 est getMethodName(int depth) et
  • 2 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.

2 votes

Il ne dit que "principal" pour moi. :-/

0 votes

@Amigable : avez vous essayé d'imprimer le tout StackTraceElement à des fins de débogage et pour voir si 'main' est la bonne méthode ?

7 votes

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 .

89voto

virgo47 Points 916

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

1 votes

Cela reste subtilement dépendant du fournisseur. La JVM n'est pas tenue de fournir des données fiables pour ce code.

6 votes

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.

1 votes

Cette option semble la plus robuste de toutes celles présentées ici, malgré les dépendances.

47voto

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

Le nom aura la valeur foo.

5 votes

Local.class.getEnclosingMethod() était nul. jdk1.6.0_31, play 1.2.5

0 votes

@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

0 votes

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.com

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.

Powered by:

X