使用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

相關文章
相關標籤/搜索