模块 java.base
 java.lang

类 StackWalker

java.lang.Object
java.lang.StackWalker

public final class StackWalker extends Object
堆栈步行者。

walk 方法为当前线程打开 StackFrame 的顺序流,然后应用给定的函数遍历 StackFrame 流。流按顺序报告堆栈帧元素,从表示生成堆栈的执行点的最顶层帧到最底层帧。 StackFrame 流在 walk 方法返回时关闭。如果尝试重用已关闭的流,将抛出 IllegalStateException

StackWalkerstack walking options 决定了要返回的StackFrame 对象的信息。默认情况下,反射 API 和实现类的堆栈帧是 hiddenStackFrame 有可用的类名和方法名,但没有 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
  • 方法详情

    • getInstance

      public static StackWalker  getInstance()
      返回一个 StackWalker 实例。

      StackWalker 配置为跳过所有 隐藏帧,不保留任何 类参考

      返回:
      a StackWalker 配置为跳过所有 隐藏帧 并且不保留任何 类参考
    • getInstance

      public static StackWalker  getInstance(StackWalker.Option  option)
      返回一个带有给定选项的StackWalker实例,指定它可以访问的堆栈帧信息。

      如果存在安全管理器并且给定的 optionOption.RETAIN_CLASS_REFERENCE ,它会为 RuntimePermission("getStackWalkerWithClassReference") 调用它的 checkPermission 方法。

      参数:
      option - stack walking option
      返回:
      StackWalker 配置了给定的选项
      抛出:
      SecurityException - 如果安全管理器存在且其 checkPermission 方法拒绝访问。
    • getInstance

      public static StackWalker  getInstance(Set <StackWalker.Option > options)
      返回一个 StackWalker 实例,其中给定的 options 指定它可以访问的堆栈帧信息。如果给定的 options 为空,则此 StackWalker 配置为跳过所有 隐藏帧 并且不保留任何 类参考

      如果存在安全管理器并且给定的 options 包含 Option.RETAIN_CLASS_REFERENCE ,它会为 RuntimePermission("getStackWalkerWithClassReference") 调用其 checkPermission 方法。

      参数:
      options - stack walking option
      返回:
      a StackWalker 配置了给定的选项
      抛出:
      SecurityException - 如果安全管理器存在且其 checkPermission 方法拒绝访问。
    • getInstance

      public static StackWalker  getInstance(Set <StackWalker.Option > options, int estimateDepth)
      返回一个 StackWalker 实例,其中给定的 options 指定它可以访问的堆栈帧信息。如果给定的 options 为空,则此 StackWalker 配置为跳过所有 隐藏帧 并且不保留任何 类参考

      如果存在安全管理器并且给定的 options 包含 Option.RETAIN_CLASS_REFERENCE ,它会为 RuntimePermission("getStackWalkerWithClassReference") 调用其 checkPermission 方法。

      estimateDepth 指定了 StackWalker 将遍历的堆栈帧的估计数量,StackWalker 可以用作缓冲区大小的提示。

      参数:
      options - stack walking options
      estimateDepth - 估计要遍历的堆栈帧数。
      返回:
      a StackWalker 配置了给定的选项
      抛出:
      IllegalArgumentException - 如果 estimateDepth <= 0
      SecurityException - 如果安全管理器存在且其 checkPermission 方法拒绝访问。
    • walk

      public <T> T walk(Function <? super Stream <StackWalker.StackFrame >,? extends T> function)
      将给定函数应用于当前线程的 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

      public void forEach(Consumer <? super StackWalker.StackFrame > action)
      对当前线程的StackFrame流的每个元素执行给定的动作,从栈顶帧开始遍历,也就是调用这个forEach方法的方法。

      这个方法相当于调用

      walk(s -> { s.forEach(action); return null; });
      参数:
      action - 要对当前线程堆栈的每个 StackFrame 执行的操作
    • getCallerClass

      public Class <?> 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 方法从堆栈上最后一帧的方法调用时。