Recherche…


Introduction

Avant Java 9, l'accès aux cadres de la pile de threads était limité à une classe interne sun.reflect.Reflection . Plus précisément, la méthode sun.reflect.Reflection::getCallerClass . Certaines bibliothèques s'appuient sur cette méthode qui est déconseillée.

Une API standard de remplacement est maintenant prévue dans 9 JDK via java.lang.StackWalker classe, et est conçu pour être efficace en permettant un accès paresseux aux cadres de la pile. Certaines applications peuvent utiliser cette API pour parcourir la pile d'exécution et filtrer les classes.

Imprimer tous les cadres de pile du thread en cours

Ce qui suit imprime tous les cadres de pile du thread en cours:

1  package test;
2  
3  import java.lang.StackWalker.StackFrame;
4  import java.lang.reflect.InvocationTargetException;
5  import java.lang.reflect.Method;
6  import java.util.List;
7  import java.util.stream.Collectors;
8  
9  public class StackWalkerExample {
10 
11    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
12        Method fooMethod = FooHelper.class.getDeclaredMethod("foo", (Class<?>[])null);
13        fooMethod.invoke(null, (Object[]) null);
14    }
15 }
16
17 class FooHelper {
18    protected static void foo() {
19        BarHelper.bar();
20    }
21 }
22 
23 class BarHelper {
24    protected static void bar() {
25        List<StackFrame> stack = StackWalker.getInstance()
26                .walk((s) -> s.collect(Collectors.toList()));
27        for(StackFrame frame : stack) {
28            System.out.println(frame.getClassName() + " " + frame.getLineNumber() + " " + frame.getMethodName());
29        }
30    }
31 }

Sortie:

test.BarHelper 26 bar
test.FooHelper 19 foo
test.StackWalkerExample 13 main

Imprimer la classe d'appelant en cours

Ce qui suit imprime la classe d'appelante actuelle. Notez que dans ce cas, le StackWalker doit être créé avec l'option RETAIN_CLASS_REFERENCE , afin que Class instances de Class soient conservées dans les objets StackFrame . Sinon, une exception se produirait.

public class StackWalkerExample {

    public static void main(String[] args) {
        FooHelper.foo();
    }

}

class FooHelper {
    protected static void foo() {
        BarHelper.bar();
    }
}

class BarHelper {
    protected static void bar() {
        System.out.println(StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE).getCallerClass());
    }
}

Sortie:

class test.FooHelper

Montrer la réflexion et autres cadres cachés

Quelques autres options permettent aux traces de pile d'inclure des cadres d'implémentation et / ou de réflexion. Cela peut être utile à des fins de débogage. Par exemple, nous pouvons ajouter l'option SHOW_REFLECT_FRAMES à l'instance StackWalker lors de la création, afin que les cadres des méthodes de réflexion soient également imprimés:

package test;

import java.lang.StackWalker.Option;
import java.lang.StackWalker.StackFrame;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.Collectors;

public class StackWalkerExample {

    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        Method fooMethod = FooHelper.class.getDeclaredMethod("foo", (Class<?>[])null);
        fooMethod.invoke(null, (Object[]) null);
    }
}

class FooHelper {
    protected static void foo() {
        BarHelper.bar();
    }
}

class BarHelper {
    protected static void bar() {
        // show reflection methods
        List<StackFrame> stack = StackWalker.getInstance(Option.SHOW_REFLECT_FRAMES)
                .walk((s) -> s.collect(Collectors.toList()));
        for(StackFrame frame : stack) {
            System.out.println(frame.getClassName() + " " + frame.getLineNumber() + " " + frame.getMethodName());
        }
    }
}

Sortie:

test.BarHelper 27 bar
test.FooHelper 20 foo
jdk.internal.reflect.NativeMethodAccessorImpl -2 invoke0
jdk.internal.reflect.NativeMethodAccessorImpl 62 invoke
jdk.internal.reflect.DelegatingMethodAccessorImpl 43 invoke
java.lang.reflect.Method 563 invoke
test.StackWalkerExample 14 main

Notez que les numéros de ligne de certaines méthodes de réflexion peuvent ne pas être disponibles. StackFrame.getLineNumber() peut donc renvoyer des valeurs négatives.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow