1.Java 9以前堆栈遍历到目前为止,官方解决方案是获取当前线程并调用其getStackTrace()方法:

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

另一个智能解决方案涉及.抛出异常并从中提取堆栈跟踪信息。 但是,无法操纵结果,它会立即打印出来:

new Exception().printStackTrace();

两种解决方案都存在同样的问题——它们都急切地捕获整个堆栈的快照,可不方便使用。

2. JEP-259: Stack-Walking API

JEP-259应该解决这些问题,而且确实如此。 新的API提供了一种使用Stream API懒惰地遍历堆栈跟踪的便捷方法。

我们可以像这样轻松地创建StackWalker实例:

StackWalker stack = StackWalker.getInstance();

此外,我们可以提供一些初始选项:

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

如果我们想要遍历整个堆栈,那只需要调用forEach()方法:

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

3. StackWalker.StackFrame

如果我们查看Java 1.4的StackTraceElement——它几乎是一个包含有关声明类、方法名、类加载器名等的详细字符串信息。

StackWalker.StackFrame是一个更加类型安全友好的升级,在其上面提到了丰富的方法:

public Class> getDeclaringClass();

public MethodType getMethodType();…甚至可这样:

public StackTraceElement toStackTraceElement();

4.示例

让我们将前面那些付诸实践,来创建一个简单的调用层次结构

(代码包和类名:com.nd.stackwalker. StackWalker):

public static void main(String[] args) {

foo();

}

private static void foo() {

bar();

}

private static void bar() {

java.lang.StackWalker

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

.forEach(System.out::println);

}

如果我们在IDE中(jshell运行显示会不一样,这个它的处理模式有关)中运行它,结果将是(注意堆栈元素的顺序):

com.nd.stackwalker.StackWalker.bar(StackWalker.java:22)

com.nd.stackwalker.StackWalker.foo(StackWalker.java:17)

com.nd.stackwalker.StackWalker.main(StackWalker.java:14)

5.高级特性如果我们想利用惰性或帧过滤,我们可以使用另一个名为walk()的专用API方法,它允许我们使用Stream API来方便地遍历堆栈。 在阅读本文时,您可能想象walk()方法只是返回一个Stream实例。事实并非如此。

实际的签名是:

public T walk(Function super Stream, ? extends T> function)

还有一个很好的理由使它成为这种方式——堆栈需要被冻结以便遍历它,并且这发生在walk()方法调用的范围内 - 所以使用基于函数接口的模板方法实现这一目标是有意义的 。

即使你试图通过返回一个Stream实例来欺骗它,它也无法使用(自己试试看!)。

一旦我们知道了这个限制,我们只受我们的想象力和Stream API功能的约束。例如,我们可以优雅地跳过一些帧,然后挑选第一个遇到的帧:

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);

// 结果如下:

com.nd.stackwalker.StackWalker.main(StackWalker.java:17)

6.完整代码清单

/*

*测试堆栈遍历

*/

package com.nd.stackwalker;

import java.util.stream.Collectors;

/**

*

* @author Solo Cui

*/

public class StackWalker {

public static void main(String[] args) {

foo();

}

private static void foo() {

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);//第一次运行,注释掉

//bar();//第二次运行注释掉

}

private static void bar() {

java.lang.StackWalker

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

.forEach(System.out::println);

}

}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对脚本之家的支持。如果你想了解更多相关内容请查看下面相关链接

java遍历栈_Java中使用StackWalker和Stream API进行堆栈遍历相关推荐

  1. java steam 去重_Java中对List去重 Stream去重的解决方法

    问题 当下互联网技术成熟,越来越多的趋向去中心化.分布式.流计算,使得很多以前在数据库侧做的事情放到了Java端.今天有人问道,如果数据库字段没有索引,那么应该如何根据该字段去重?大家都一致认为用Ja ...

  2. java入栈_java中代码块的执行,也会有入栈的步骤吗?

    首先这个问题很有意思,不过题主没具体指明放在何处的代码块. 这里至少有三种情况,第一种就是在普通的方法里面,第二种是实例初始化代码块,第三种是静态初始化代码块. 第一种情况 使用javap反汇编了一下 ...

  3. java steam 去重_Java中对List去重, Stream去重

    问题 当下互联网技术成熟,越来越多的趋向去中心化.分布式.流计算,使得很多以前在数据库侧做的事情放到了Java端.今天有人问道,如果数据库字段没有索引,那么应该如何根据该字段去重?大家都一致认为用Ja ...

  4. java静态方法 问题_Java中堆、栈,静态方法和非静态方法的速度问题

    一.堆和栈的速度性能分析 堆和栈是JVM内存模型中的2个重要组成部分,自己很早以前也总结过堆和栈的区别,基本都是从存储内容,存储空间大小,存储速度这几个方面来理解的,但是关于堆和栈的存储速度,只知道堆 ...

  5. java如何遍历字典_Java中如何遍历Map对象的4种方法

    在Java中如何遍历Map对象 How to Iterate Over a Map in Java 在java中遍历Map有不少的方法.我们看一下最常用的方法及其优缺点. 既然java中的所有map都 ...

  6. java内存堆和栈_java中堆,栈主要区别及内存存储

    java堆.栈.堆栈的区别 1.栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. 2. 栈的优势是,存取速度 ...

  7. java filefilter递归_Java中的递归+文件过滤器

    直接递归称为方法自身调用自己 间接递归可以A方法调用B方法,B方法调用方法,C方法调用A方法. 注意事项: 递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出. 在递归中虽然有限定条件, ...

  8. java 注解开发_Java中的注解到底是如何工作的?

    作者:人晓 www.importnew.com/10294.html 自Java5.0版本引入注解之后,它就成为了Java平台中非常重要的一部分.开发过程中,我们也时常在应用代码中会看到诸如@Over ...

  9. java 不知道类名_Java 中获取类名的三种方法,你知道几种?

    之前我们分享过Java高级篇--深入浅出Java类加载机制这篇文章,今天来带你了解获取类名的三种方法. 获取类名的方法 Java 中获取类名的方式主要有以下三种. getName() 返回的是虚拟机里 ...

最新文章

  1. 安装hadoop下的sqoop1.99.3及配置问题全解决
  2. tensorflow量化感知训练_tensorflow模型量化实例
  3. 传闻或成真!这款新iPhone真就要停产了...
  4. 3d 自动生成物体_根据 2D 图片自动生成 3D 图书封面的牛逼工具
  5. word2016取消首字母大写 带图详细讲解
  6. Ubuntu10.0.4下CyanogenMod编译环境的搭建和可刷机文件的编译及打包
  7. centos安装libconfig
  8. java 运行 依赖_java – 运行时中的依赖项确定
  9. 最简单音乐播放器,还有歌词
  10. 利用intellij idea工具如何反编译.jar
  11. Linux 》编译器gcc/g++,调试器gdb
  12. phpstudy 运行PHP项目
  13. 大数据解决方案:Hadoop监控
  14. stm32L152 使用内部内部flash做EEPROM 出FLASH_ERROR_WRP问题及解决办法
  15. 【shell】Cshell
  16. 关于async await 等任务队列插话
  17. 520、Java Spring Cloud Alibaba -【Spring Cloud Alibaba Zuul】 2021.11.02
  18. linux ftp下载文件到本地,如何使用get指令利用FTP下载文件到本地
  19. odoo12 学习: 无效视图 xxxx xxxx xxxx 定义 False
  20. ADB命令大全--自学留存

热门文章

  1. void*与int互转
  2. boost库之tcp client 回调不正常
  3. jsp打印日志完整配置
  4. 爬虫架构师得逆袭之路
  5. android app电量分析,如何计算android app的耗电量?
  6. vc++获取的蓝牙设备信息中rssi的值_Android低功耗蓝牙总结
  7. idea设置类注释和方法注释
  8. redis 经纬度_原来用Redis实现查找附近的人这么容易
  9. 云南林业职业技术学院计算机考试试题,云南林业职业技术学院单招模拟题(含解析)9.docx...
  10. 第三讲,我们来谈谈:“二进制的负数”