使用Java新功能StackWalker

StackWalking API是最近添加到Java中的最酷功能之一
在Java9之前,要獲得棧信息辦法是:獲取當前線程並調用其getStackTrace()方法
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();

另一個智能解決方案涉及...拋出異常並從中提取堆棧跟蹤信息。但是,無法操縱結果,它只會立即輸出:
newException().printStackTrace();

兩種解決方案都存在同樣的問題 - 它們只是捕獲了整個堆棧的快照,並且不方便使用。
JEP-259 提出Stack-Walking API可以解決這些問題。新的API提供了一種使用Stream API惰性地遍歷堆棧跟蹤的便捷方法。
我們可以像以下一樣輕鬆創建StackWalker實例:
StackWalkerstack = StackWalker.getInstance();

還可以定製一點初始化信息:
StackWalkerstack = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);

如果我們想要遍歷整個堆棧,只需調用forEach()方法:
stack.forEach(System.out::println);

如果我們查看Java 1.4的StackTraceElement - 它幾乎是一個包含有關聲明類,方法名,類加載器名等的字符串信息的DTO。
StackWalker.StackFrame是一個更加類型安全友好的升級,豐富了以下方法:
public Class getDeclaringClass();

public MethodType getMethodType();

public StackTraceElement toStackTraceElement();

讓我們將其付諸實踐並創建一個簡單的調用層次結構:
public static voidmain(String[] args){

foo();

}

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章