Java Language
API стека
Поиск…
Вступление
До Java 9 доступ к кадрам стека потоков был ограничен внутренним классом sun.reflect.Reflection
. В частности, метод sun.reflect.Reflection::getCallerClass
. Некоторые библиотеки полагаются на этот метод, который устарел.
Альтернативный стандарт API , теперь предоставляется в JDK 9 через java.lang.StackWalker
класса, и предназначен , чтобы быть эффективными, позволяя ленивый доступ к кадрам стеки. Некоторые приложения могут использовать этот API для прохождения стека выполнения и фильтрации по классам.
Печать всех кадров стека текущего потока
Следующее выводит все кадры стека текущего потока:
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 }
Выход:
test.BarHelper 26 bar
test.FooHelper 19 foo
test.StackWalkerExample 13 main
Распечатать текущий класс вызывающего абонента
Следующее выводит текущий класс вызывающего абонента. Обратите внимание, что в этом случае StackWalker
необходимо создать с помощью опции RETAIN_CLASS_REFERENCE
, чтобы экземпляры Class
сохранялись в объектах StackFrame
. В противном случае произойдет исключение.
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());
}
}
Выход:
class test.FooHelper
Отображение отражения и других скрытых фреймов
Пара других опций позволяет трассировать трассировки стека реализации и / или отражения. Это может быть полезно для целей отладки. Например, мы можем добавить параметр SHOW_REFLECT_FRAMES
к экземпляру StackWalker
при создании, чтобы также были напечатаны кадры для отражающих методов:
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());
}
}
}
Выход:
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
Обратите внимание, что номера строк для некоторых методов отражения могут быть недоступны, поэтому StackFrame.getLineNumber()
может возвращать отрицательные значения.