Java8利用stream流实现递归遍历树形结构
短信预约 -IT技能 免费直播动态提醒
利用stream流实现递归遍历树形结构
1. 什么是树形结构
下面用一张图片说明:
在这张表中,每条数据分别有自己的id和parentId,这些数据通过父与子不断连接,形成了一个树结构。
2. 如何通过stream流处理树形结构
我们最终需要的结果是一个树形的json串,如下:
话不多说,直接上代码:
这是course_category类,即数据库对应的vo:
这是CourseCategoryTreeDto类,即我们所需要的dto类:
service层代码实现如下:
@Service@Slf4jpublic class CourseCategoryServiceImpl implements CourseCategoryService { @Autowired private CourseCategoryMapper courseCategoryMapper; @Override public List<CourseCategoryTreeDto> queryTreeNodes(String id) { // 获取数据库中的数据,这里建议先排序一下,会快很多 List<CourseCategoryTreeDto> categoryTreeDtos = courseCategoryMapper.selectTreeNodes(id); // 调用递归函数获取树形结构,并排除掉表中的根节点:m -> m.getParentid().equals("1") List<CourseCategoryTreeDto> courseCategoryTreeDtos = categoryTreeDtos.stream() .filter( m -> m.getParentid().equals("1")) .peek(m -> m.setChildrenTreeNodes(getChildrens(m, categoryTreeDtos))) .collect(Collectors.toList()); return courseCategoryTreeDtos; } // 递归函数 过滤拿到父节点为当前节点的节点,递归加入到当前节点的子节点中,再收集起来 private List<CourseCategoryTreeDto> getChildrens(CourseCategoryTreeDto root, List<CourseCategoryTreeDto> all){ List<CourseCategoryTreeDto> childrens = all.stream() .filter( m -> Objects.equals(m.getParentid(), root.getId())) // peek方法返回由该流的元素组成的流,并对每个元素执行所提供的 Consumer操作方法 // peek和foreach在功能上类似,但foreach执行完函数不做其他操作了,peek完还可以继续对stream进行其它操作 // 这篇文章解释的比较清晰:https://blog.csdn.net/VoisSurTonChemin/article/details/122378636 .peek(m -> m.setChildrenTreeNodes(getChildrens(m, all))) .collect(Collectors.toList()); return childrens; }}
当然,不用stream流我们也可以实现,如下:
@Service@Slf4jpublic class CourseCategoryServiceImpl implements CourseCategoryService { @Autowired private CourseCategoryMapper courseCategoryMapper; @Override public List<CourseCategoryTreeDto> queryTreeNodes(String id) { // 获得根节点下所有子节点 注意 CourseCategoryTreeDto是CourseCategory的子类 // 这里获取的List实际上只是List罢了 并没有构建树形结构 需要下面的处理 List<CourseCategoryTreeDto> categoryTreeDtos = courseCategoryMapper.selectTreeNodes(id); // 定义一个list作为最终返回的数据 List<CourseCategoryTreeDto> courseCategoryTreeDtos = new ArrayList<>(); // 为了方便找子节点的父节点,我们定义一个map来存 HashMap<String, CourseCategoryTreeDto> nodeMap = new HashMap<>(); // 将数据封装到list中,只包括了根节点的直接下属节点,即实现树形结构 categoryTreeDtos.stream().forEach(item -> { // 存入hashmap中,当前节点的id和信息 nodeMap.put(item.getId(), item); String parentId = item.getParentid(); // 如果当前节点的的父节点是传过来的节点时,即为根节点的子节点时,加入该节点 // 因为根节点为0,是定义的一个无关的节点,传过去的数据应该从根节点的叶子节点开始 if(parentId.equals(id)){ courseCategoryTreeDtos.add(item); } // 此处是获取该项item的父节点的ChildrenTreeNodes,将该项加入对应父节点的的ChildrenTreeNodes中 CourseCategoryTreeDto parentNode = nodeMap.get(parentId); if(parentNode != null){ List childrenTreeNodes = parentNode.getChildrenTreeNodes(); if(childrenTreeNodes == null){ parentNode.setChildrenTreeNodes(new ArrayList<CourseCategoryTreeDto>()); } parentNode.getChildrenTreeNodes().add(item); } }); }}
参考文章:
- Java8新特性-使用Stream流递归实现遍历树形结构
https://blog.csdn.net/qq_19244927/article/details/106481777 - 【Java 8 新特性】Java Stream通过peek()为每个元素提供消费函数
https://blog.csdn.net/qq_31635851/article/details/111150978 - Java stream 中 peek() 的合理用法
https://blog.csdn.net/VoisSurTonChemin/article/details/122378636
来源地址:https://blog.csdn.net/qq_51534363/article/details/128795991
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341