Ricerca…


introduzione

Prima di Java 9, l'accesso ai frame dello stack di thread era limitato a una classe interna sun.reflect.Reflection . In particolare il metodo sun.reflect.Reflection::getCallerClass . Alcune librerie si basano su questo metodo che è deprecato.

Un'API standard alternativa è ora disponibile in JDK 9 attraverso il java.lang.StackWalker classe, ed è progettato per essere efficiente, consentendo l'accesso pigro per stack frame. Alcune applicazioni possono utilizzare questa API per attraversare lo stack di esecuzione e filtrare sulle classi.

Stampa tutti i frame stack del thread corrente

Le seguenti stampe impilano tutti i frame del thread corrente:

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 }

Produzione:

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

Stampa la classe corrente dei chiamanti

Di seguito viene stampato l'attuale classe del chiamante. Nota che in questo caso, StackWalker deve essere creato con l'opzione RETAIN_CLASS_REFERENCE , in modo che le istanze della Class vengano mantenute negli oggetti StackFrame . Altrimenti si verificherebbe un'eccezione.

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

Produzione:

class test.FooHelper

Mostrando la riflessione e altri fotogrammi nascosti

Un paio di altre opzioni consentono alle tracce dello stack di includere cornici di implementazione e / o riflessione. Questo può essere utile per scopi di debug. Per esempio, possiamo aggiungere lo SHOW_REFLECT_FRAMES opzione per lo StackWalker esempio al momento della creazione, in modo che le cornici per i metodi riflettenti vengono stampati così:

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

Produzione:

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

Nota che i numeri di linea per alcuni metodi di riflessione potrebbero non essere disponibili, quindi StackFrame.getLineNumber() può restituire valori negativi.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow