Java Language
Stack-Walking-API
Suche…
Einführung
Vor Java 9 war der Zugriff auf die sun.reflect.Reflection
auf eine interne Klasse sun.reflect.Reflection
. Speziell die Methode sun.reflect.Reflection::getCallerClass
. Einige Bibliotheken verlassen sich auf diese Methode, die veraltet ist.
Ein alternativer Standard - API wird nun in JDK 9 über die vorgesehen java.lang.StackWalker
Klasse und wird , indem man lazy Zugang zu dem Stapelrahmen sein , effizient gestaltet. Einige Anwendungen können diese API verwenden, um den Ausführungsstapel zu durchsuchen und nach Klassen zu filtern.
Drucken Sie alle Stack-Frames des aktuellen Threads
Folgendes druckt alle Stack-Frames des aktuellen Threads:
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 }
Ausgabe:
test.BarHelper 26 bar
test.FooHelper 19 foo
test.StackWalkerExample 13 main
Aktuelle Anruferklasse drucken
Im Folgenden wird die aktuelle Anruferklasse gedruckt. Beachten Sie, dass in diesem Fall die StackWalker
mit der Option erstellt werden muss RETAIN_CLASS_REFERENCE
, so dass die Class
in den zurückgehalten werden StackFrame
Objekte. Andernfalls würde eine Ausnahme auftreten.
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());
}
}
Ausgabe:
class test.FooHelper
Reflektion und andere verborgene Frames anzeigen
Bei einigen anderen Optionen können Stack-Spuren Implementierungs- und / oder Reflektionsframes enthalten. Dies kann für Debugging-Zwecke hilfreich sein. Zum Beispiel können wir die Add SHOW_REFLECT_FRAMES
Option zum StackWalker
Beispiel bei der Erstellung, so dass der Rahmen für die reflektierenden Methoden als auch gedruckt werden:
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());
}
}
}
Ausgabe:
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
Beachten Sie, dass Zeilennummern für einige Reflektionsmethoden möglicherweise nicht verfügbar sind, sodass StackFrame.getLineNumber()
negative Werte zurückgeben kann.