walk 方法为当前线程打开 StackFrame 的顺序流,然后应用给定的函数遍历 StackFrame 流。流按顺序报告堆栈帧元素,从表示生成堆栈的执行点的最顶层帧到最底层帧。 StackFrame 流在 walk 方法返回时关闭。如果尝试重用已关闭的流,将抛出 IllegalStateException。
StackWalker的stack walking options 决定了要返回的StackFrame 对象的信息。默认情况下,反射 API 和实现类的堆栈帧是 hidden 和 StackFrame 有可用的类名和方法名,但没有 Class reference 。
StackWalker 是线程安全的。多个线程可以共享一个 StackWalker 对象来遍历自己的堆栈。根据请求的选项,在创建 StackWalker 时执行权限检查。在堆栈遍历时不会进行进一步的权限检查。
- API 注意:
-
示例
1. 过滤一个已知的实现类列表来查找第一个调用者:
StackWalker walker = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE); Optional<Class<?>> callerClass = walker.walk(s -> s.map(StackFrame::getDeclaringClass) .filter(interestingClasses::contains) .findFirst());2. 快照当前线程的前 10 个栈帧,
除非另有说明,否则将List<StackFrame> stack = StackWalker.getInstance().walk(s -> s.limit(10).collect(Collectors.toList()));null参数传递给此StackWalker类中的构造函数或方法将导致抛出NullPointerException。 - 自从:
- 9
-
内部类总结
内部类修饰符和类型类描述static enumStack walker 选项配置由StackWalker获取的 栈帧 信息。static interfaceStackFrame对象表示StackWalker返回的方法调用。 -
方法总结
修饰符和类型方法描述voidforEach(Consumer<? super StackWalker.StackFrame> action) 对当前线程的StackFrame流的每个元素执行给定的动作,从栈顶帧开始遍历,也就是调用这个forEach方法的方法。Class<?>获取调用getCallerClass方法的调用方的Class对象。static StackWalker返回一个StackWalker实例。static StackWalkergetInstance(StackWalker.Option option) 返回一个带有给定选项的StackWalker实例,指定它可以访问的堆栈帧信息。static StackWalkergetInstance(Set<StackWalker.Option> options) 返回一个StackWalker实例,其中给定的options指定它可以访问的堆栈帧信息。static StackWalkergetInstance(Set<StackWalker.Option> options, int estimateDepth) 返回一个StackWalker实例,其中给定的options指定它可以访问的堆栈帧信息。<T> Twalk(Function<? super Stream<StackWalker.StackFrame>, ? extends T> function) 将给定函数应用于当前线程的StackFrame流,从栈顶帧开始遍历,即调用此walk方法的方法。
-
方法详情
-
getInstance
-
getInstance
返回一个带有给定选项的StackWalker实例,指定它可以访问的堆栈帧信息。如果存在安全管理器并且给定的
option是Option.RETAIN_CLASS_REFERENCE,它会为RuntimePermission("getStackWalkerWithClassReference")调用它的checkPermission方法。- 参数:
option-stack walking option- 返回:
StackWalker配置了给定的选项- 抛出:
SecurityException- 如果安全管理器存在且其checkPermission方法拒绝访问。
-
getInstance
返回一个StackWalker实例,其中给定的options指定它可以访问的堆栈帧信息。如果给定的options为空,则此StackWalker配置为跳过所有 隐藏帧 并且不保留任何 类参考。如果存在安全管理器并且给定的
options包含Option.RETAIN_CLASS_REFERENCE,它会为RuntimePermission("getStackWalkerWithClassReference")调用其checkPermission方法。- 参数:
options-stack walking option- 返回:
-
a
StackWalker配置了给定的选项 - 抛出:
SecurityException- 如果安全管理器存在且其checkPermission方法拒绝访问。
-
getInstance
返回一个StackWalker实例,其中给定的options指定它可以访问的堆栈帧信息。如果给定的options为空,则此StackWalker配置为跳过所有 隐藏帧 并且不保留任何 类参考。如果存在安全管理器并且给定的
options包含Option.RETAIN_CLASS_REFERENCE,它会为RuntimePermission("getStackWalkerWithClassReference")调用其checkPermission方法。estimateDepth指定了StackWalker将遍历的堆栈帧的估计数量,StackWalker可以用作缓冲区大小的提示。- 参数:
options-stack walking optionsestimateDepth- 估计要遍历的堆栈帧数。- 返回:
-
a
StackWalker配置了给定的选项 - 抛出:
IllegalArgumentException- 如果estimateDepth <= 0SecurityException- 如果安全管理器存在且其checkPermission方法拒绝访问。
-
walk
将给定函数应用于当前线程的StackFrame流,从栈顶帧开始遍历,即调用此walk方法的方法。StackFrame流将在此方法返回时关闭。当一个关闭的Stream<StackFrame>对象被重用时,IllegalStateException将被抛出。- API 注意:
-
例如,要找到前 10 个调用帧,首先跳过那些声明类在包
com.foo中的帧:List<StackFrame> frames = StackWalker.getInstance().walk(s -> s.dropWhile(f -> f.getClassName().startsWith("com.foo.")) .limit(10) .collect(Collectors.toList()));此方法采用
Function接受Stream<StackFrame>,而不是返回Stream<StackFrame>并允许调用者直接操作流。 Java 虚拟机可以自由重组线程的控制堆栈,例如,通过去优化。通过采用Function参数,此方法允许通过线程控制堆栈的稳定视图访问堆栈帧。并行执行被有效禁用,流管道执行只会发生在当前线程上。
- 实现注意事项:
-
该实现通过锚定特定于栈遍历的框架来稳定栈,并确保栈遍历在锚定框架之上执行。当流对象关闭或被重用时,将抛出
IllegalStateException。 - 类型参数:
T- 将函数应用于 栈帧 流的结果类型。- 参数:
function- 一个接受 栈帧 流并返回结果的函数。- 返回:
- 将函数应用于 栈帧 流的结果。
-
forEach
对当前线程的StackFrame流的每个元素执行给定的动作,从栈顶帧开始遍历,也就是调用这个forEach方法的方法。这个方法相当于调用
walk(s -> { s.forEach(action); return null; });- 参数:
action- 要对当前线程堆栈的每个StackFrame执行的操作
-
getCallerClass
获取调用getCallerClass方法的调用方的Class对象。此方法过滤 倒影框、
MethodHandle和 隐藏帧,而不管StackWalker配置的SHOW_REFLECT_FRAMES和SHOW_HIDDEN_FRAMES选项。当存在调用方框架时,应调用此方法。如果从堆栈的最底部帧调用它,将抛出
IllegalCallerException。如果此
StackWalker未配置RETAIN_CLASS_REFERENCE选项,则此方法将抛出UnsupportedOperationException。- API 注意:
-
例如,
Util::getResourceBundle代表调用者加载资源包。它调用getCallerClass来识别其方法称为Util::getResourceBundle的类。然后,它获取该类的类加载器,并使用类加载器加载资源包。本例中的调用者类是MyTool。
使用class Util { private final StackWalker walker = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE); public ResourceBundle getResourceBundle(String bundleName) { Class<?> caller = walker.getCallerClass(); return ResourceBundle.getBundle(bundleName, Locale.getDefault(), caller.getClassLoader()); } } class MyTool { private final Util util = new Util(); private void init() { ResourceBundle rb = util.getResourceBundle("mybundle"); } }walk方法查找调用者类的等效方法如下(过滤反射帧、MethodHandle和隐藏帧未在下面显示):
当从堆栈最底部帧的方法调用Optional<Class<?>> caller = walker.walk(s -> s.map(StackFrame::getDeclaringClass) .skip(2) .findFirst());getCallerClass方法时,例如,由java启动器启动的static public void main方法,或从 JNI 附加线程调用的方法,IllegalCallerException被抛出。 - 返回:
-
调用此方法的调用者的调用者的
Class对象。 - 抛出:
UnsupportedOperationException- 如果此StackWalker未配置Option.RETAIN_CLASS_REFERENCE。IllegalCallerException- 如果没有调用者帧,即当此getCallerClass方法从堆栈上最后一帧的方法调用时。
-