Java Language
Interfejs API Walking-Walking
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.