1. Obtenir une trace de pile

Obtenir une trace de pile

Le langage de programmation Java offre de nombreuses façons pour un programmeur d'obtenir des informations sur ce qui se passe dans un programme. Et pas que des mots.

Par exemple, une fois les programmes C++ compilés, ils deviennent un gros fichier rempli de code machine, et tout ce qui est disponible pour un programmeur au moment de l'exécution est l'adresse du bloc de mémoire qui contient le code machine en cours d'exécution. Pas beaucoup, disons.

Mais pour Java, même après la compilation d'un programme, les classes restent des classes, les méthodes et les variables ne disparaissent pas, et le programmeur a de nombreuses façons d'obtenir des informations sur ce qui se passe dans le programme.

Trace de la pile

Par exemple, à un moment de l'exécution d'un programme, vous pouvez connaître la classe et le nom de la méthode en cours d'exécution. Et pas seulement une méthode - vous pouvez obtenir des informations sur toute la chaîne d'appels de méthode de la méthode actuelle à la main()méthode.

Une liste composée de la méthode actuelle, de la méthode qui l'a invoquée, de la méthode qui l'a appelée, etc. est appelée une trace de pile . Vous pouvez l'obtenir avec cette déclaration :

StackTraceElement[] methods = Thread.currentThread().getStackTrace();

Vous pouvez également l'écrire sur deux lignes :

Thread current = Thread.currentThread();
StackTraceElement[] methods = current.getStackTrace();

La currentThread()méthode statique de la Threadclasse renvoie une référence à un Threadobjet, qui contient des informations sur le thread courant, c'est-à-dire le thread d'exécution en cours. Vous en apprendrez plus sur les threads dans les niveaux 17 et 18 de la quête Java Core .

Cet Threadobjet a une getStackTrace()méthode, qui renvoie un tableau d' StackTraceElementobjets, chacun contenant des informations sur une méthode. Pris ensemble, tous ces éléments forment une pile trace .

Exemple:

Code
public class Main
{
   public static void main(String[] args)
   {
      test();
   }

   public static void test()
   {
      Thread current = Thread.currentThread();
      StackTraceElement[] methods = current.getStackTrace();

      for(var info: methods)
         System.out.println(info);
   }
}
Sortie console
java.base/java.lang.Thread.getStackTrace(Thread.java:1606)
Main.test(Main.java:11)
Main.main(Main.java:5)

Comme nous pouvons le voir dans la sortie de la console de l'exemple, la getStackTrace()méthode a renvoyé un tableau de trois éléments :

  • getStackTrace()méthode de la Threadclasse
  • test()méthode de la Mainclasse
  • main()méthode de la Mainclasse

À partir de cette trace de pile, nous pouvons conclure que :

  • La Thread.getStackTrace()méthode a été appelée par la Main.test()méthode de la ligne 11 du fichier Main.java
  • La Main.test()méthode a été appelée par la Main.main()méthode de la ligne 5 du fichier Main.java
  • Personne n'a appelé la Main.main()méthode — c'est la première méthode dans la chaîne d'appels.

Soit dit en passant, seules certaines des informations disponibles étaient affichées à l'écran. Tout le reste peut être obtenu directement à partir de l' StackTraceElementobjet



2.StackTraceElement

Comme son nom l'indique, la StackTraceElementclasse a été créée pour stocker des informations sur un élément de trace de pile , c'est-à-dire une méthode dans le fichier stack trace.

Cette classe possède les méthodes d'instance suivantes :

Méthode Description
String getClassName()
Renvoie le nom de la classe
String getMethodName()
Renvoie le nom de la méthode
String getFileName()
Renvoie le nom du fichier (un fichier peut contenir plusieurs classes)
int getLineNumber()
Renvoie le numéro de ligne dans le fichier où la méthode a été appelée
String getModuleName()
Renvoie le nom du module (cela peut être null)
String getModuleVersion()
Renvoie la version du module (cela peut être null)

Ils peuvent vous aider à obtenir des informations plus complètes sur la pile d'appels actuelle :

Code Sortie console Note
public class Main
{
   public static void main(String[] args)
   {
      test();
   }

   public static void test()
   {
      Thread current = Thread.currentThread();
      StackTraceElement[] methods = current.getStackTrace();

      for(StackTraceElement info: methods)
      {
         System.out.println(info.getClassName());
         System.out.println(info.getMethodName());

         System.out.println(info.getFileName());
         System.out.println(info.getLineNumber());

         System.out.println(info.getModuleName());
         System.out.println(info.getModuleVersion());
         System.out.println();
      }
   }
}
java.lang.Thread
getStackTrace
Thread.java
1606
java.base
11.0.2

Main
test
Main.java
11
null
null

Main
main
Main.java
5
null
null
nom de la classe nom
de la méthode nom
du fichier
numéro de ligne
nom
du module version du

module nom de la classe
nom de la méthode
nom du
fichier numéro de la ligne nom du module version du module nom de la classe nom de la méthode nom du fichier numéro de la ligne nom du module version du module










3. Pile

Vous savez déjà ce qu'est une trace de pile , mais qu'est-ce qu'une pile (classe Stack) ?

Une pile est une structure de données à laquelle vous pouvez ajouter des éléments et à partir de laquelle vous pouvez récupérer des éléments. Ce faisant, vous ne pouvez prendre que des éléments de la fin : vous prenez d'abord le dernier ajouté, puis l'avant-dernier ajouté, etc.

La pile de noms elle-même suggère ce comportement, comme la façon dont vous interagiriez avec une pile de papiers. Si vous mettez les feuilles 1, 2 et 3 en pile, vous devez les récupérer dans l'ordre inverse : d'abord la troisième feuille, puis la deuxième, et ensuite seulement la première.

Java a même une classe spéciale de collection Stack avec le même nom et le même comportement. Cette classe partage beaucoup de comportements avec ArrayListet LinkedList. Mais il a également des méthodes qui implémentent le comportement de la pile :

Méthodes Description
T push(T obj)
Ajoute l' objélément en haut de la pile
T pop()
Prend l'élément du haut de la pile (la profondeur de la pile diminue)
T peek()
Renvoie l'élément en haut de la pile (la pile ne change pas)
boolean empty()
Vérifie si la collection est vide
int search(Object obj)
Recherche un objet dans la collection et renvoie sonindex

Exemple:

Code Contenu de la pile (le haut de la pile est à droite)
Stack<Integer> stack = new Stack<Integer>();
stack.push(1);
stack.push(2);
stack.push(3);
int x = stack.pop();
stack.push(4);
int y = stack.peek();
stack.pop();
stack.pop();

[1]
[1, 2]
[1, 2, 3]
[1, 2]
[1, 2, 4]
[1, 2, 4]
[1, 2]
[1]

Les piles sont assez souvent utilisées en programmation. C'est donc une collection utile.



4. Affichage d'une trace de pile lors de la gestion des exceptions

Pourquoi une liste d'appels de méthode est-elle appelée une trace de pile ? Parce que si vous considérez la liste des méthodes comme une pile de feuilles de papier avec des noms de méthode, lorsque vous appelez la méthode suivante, vous ajoutez une feuille avec le nom de cette méthode à la pile. Et la feuille de papier suivante va au-dessus de cela, et ainsi de suite.

Lorsqu'une méthode se termine, la feuille en haut de la pile est supprimée. Vous ne pouvez pas retirer une feuille du milieu de la pile sans retirer toutes les feuilles au-dessus. De même, vous ne pouvez pas terminer une méthode au milieu d'une chaîne d'appels sans terminer toutes les méthodes qu'elle a appelées.

Des exceptions

Une autre utilisation intéressante des piles est lors de la gestion des exceptions.

Lorsqu'une erreur se produit dans un programme et qu'une exception est levée , l'exception contient la trace de pile actuelle - un tableau constitué d'une liste de méthodes commençant, à partir de la méthode principale et se terminant par la méthode où l'erreur s'est produite. Il y a même la ligne où l'exception a été levée !

Cette trace de pile est stockée à l'intérieur de l'exception et peut être facilement récupérée à l'aide de la méthode suivante :StackTraceElement[] getStackTrace()

Exemple:

Code Note
try
{
   // An exception may occur here
}
catch(Exception e)
{
   StackTraceElement[] methods = e.getStackTrace()
}




Intercepter l'exception

Obtenir la trace de la pile qui existait lorsque l'erreur s'est produite.

C'est une méthode de la Throwableclasse, donc tous ses descendants (c'est-à-dire toutes les exceptions) ont la getStackTrace()méthode. Super pratique, hein ?

Afficher la trace de la pile de l'exception

Soit dit en passant, la Throwableclasse a une autre méthode pour travailler avec les traces de pile, une méthode qui affiche toutes les informations de trace de pile stockées dans l'exception. Il s'appelle printStackTrace().

Très commodément, vous pouvez l'appeler sur n'importe quelle exception.

Exemple:

Code
try
{
   // An exception may occur here
}
catch(Exception e)
{
   e.printStackTrace();
}
Sortie console
java.base/java.lang.Thread.getStackTrace(Thread.java:1606)
Main.test(Main.java:11)
Main.main(Main.java:5)