Szukaj…


Wprowadzenie

Przed sun.reflect.Reflection Java 9 dostęp do ramek stosów wątków był ograniczony do wewnętrznej klasy sun.reflect.Reflection . W szczególności metoda sun.reflect.Reflection::getCallerClass . Niektóre biblioteki korzystają z tej metody, która jest przestarzała.

Alternatywnym standardowe API są obecnie dostępne w JDK 9 poprzez java.lang.StackWalker klasy i ma być skuteczny, umożliwiając dostęp do lazy ramek stos. Niektóre aplikacje mogą używać tego interfejsu API do przeglądania stosu wykonywania i filtrowania klas.

Wydrukuj wszystkie ramki stosu bieżącego wątku

Następujące polecenie drukuje wszystkie ramki stosu bieżącego wątku:

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 }

Wynik:

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

Wydrukuj bieżącą klasę dzwoniącego

Poniżej wydrukowano aktualną klasę dzwoniącego. Zauważ, że w takim przypadku StackWalker musi zostać utworzony z opcją RETAIN_CLASS_REFERENCE , aby instancje Class były zachowane w obiektach StackFrame . W przeciwnym razie wystąpiłby wyjątek.

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

Wynik:

class test.FooHelper

Pokazuje odbicie i inne ukryte ramki

Kilka innych opcji pozwala, aby ślady stosu obejmowały ramki implementacyjne i / lub refleksyjne. Może to być przydatne do celów debugowania. Na przykład możemy dodać opcję SHOW_REFLECT_FRAMES do instancji StackWalker po utworzeniu, aby drukowane były również ramki metod refleksyjnych:

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

Wynik:

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

Zauważ, że numery wierszy dla niektórych metod odbicia mogą być niedostępne, więc StackFrame.getLineNumber() może zwracać wartości ujemne.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow