使用Java新功能StackWalker

StackWalking API是最近添加到Java中的最酷功能之一

在Java9以前,要得到栈信息办法是:获取当前线程并调用其getStackTrace()方法

StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();java

另外一个智能解决方案涉及...抛出异常并从中提取堆栈跟踪信息。可是,没法操纵结果,它只会当即输出:

newException().printStackTrace();安全

两种解决方案都存在一样的问题 - 它们只是捕获了整个堆栈的快照,而且不方便使用。

JEP-259 提出Stack-Walking API能够解决这些问题。新的API提供了一种使用Stream API惰性地遍历堆栈跟踪的便捷方法。

咱们能够像如下同样轻松建立StackWalker实例:

StackWalkerstack = StackWalker.getInstance();ui

还能够定制一点初始化信息:

StackWalkerstack = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);spa

若是咱们想要遍历整个堆栈,只需调用forEach()方法:

stack.forEach(System.out::println);.net

若是咱们查看Java 1.4的StackTraceElement - 它几乎是一个包含有关声明类,方法名,类加载器名等的字符串信息的DTO。

StackWalker.StackFrame是一个更加类型安全友好的升级,丰富了如下方法:

public Class getDeclaringClass();线程

public MethodType getMethodType();接口

public StackTraceElement toStackTraceElement();ip

让咱们将其付诸实践并建立一个简单的调用层次结构:

public static voidmain(String[] args){字符串

foo();get

}

private static voidfoo(){

bar();

}

private static voidbar(){

java.lang.StackWalker

.getInstance(java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE)

.forEach(System.out::println);

}

运行这段代码得到:

com.pivovarit.stack.StackWalker.bar(StackWalker.java:16)com.pivovarit.stack.StackWalker.foo(StackWalker.java:10)com.pivovarit.stack.StackWalker.main(StackWalker.java:6)

高级功能

若是咱们想利用懒加载或frame过滤,咱们可使用另外一个名为walk()的专用API方法,它容许咱们使用Stream API来方便地遍历堆栈。在阅读本文时,您可能想象walk()方法只是返回一个Stream实例 - 嗯,事实并不是如此。

这个方法实际是:

publicTwalk(FunctionsuperStream, ?extendsT>function)

使用基于Function接口的模板方法是有意义的:当调用walk()方法时,堆栈须要被冻结才能遍历它。

咱们能够优雅地跳过一些frame,并选择第一个遇到的frame:

java.lang.StackWalker

.getInstance(java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE)

.walk(s -> s.skip(1).limit(1).collect(Collectors.toList()))

.forEach(System.out::println);

// result

com.pivovarit.stack.StackWalker.foo(StackWalker.java:12)

转:https://www.tuicool.com/articles/InAf6vb

相关文章
相关标签/搜索