詳解如何使用Java流API構(gòu)建樹形結(jié)構(gòu)數(shù)據(jù)
簡介
在實(shí)際開發(fā)中,構(gòu)建樹狀層次結(jié)構(gòu)是常見需求,如組織架構(gòu)、目錄結(jié)構(gòu)或菜單系統(tǒng)。本教案通過解析給定的Java代碼,展示如何使用Java 8 Stream API將扁平化的菜單數(shù)據(jù)轉(zhuǎn)換為具有層級關(guān)系的樹形結(jié)構(gòu)。
1. 核心類定義 - Menu
@Data @NoArgsConstructor @AllArgsConstructor static class Menu { private Long id; private String name; private Long parentId; private List<Menu> children; }
提示:此處定義了一個名為Menu的類,它包含了菜單項(xiàng)的基本屬性,包括ID、名稱、父菜單ID以及一個用于存儲子菜單項(xiàng)的列表。
2. main方法解析及實(shí)現(xiàn)功能
輸入?yún)?shù):
List<Menu> menus:包含所有菜單項(xiàng)的集合。
輸出結(jié)果:
List<Menu>:一個僅包含頂級菜單項(xiàng)的列表,每個頂級菜單項(xiàng)已填充了其下級子菜單。
public static void main(String[] args) { List<Menu> menus = menusData(); /** * 從菜單列表中篩選出頂級菜單,并為其添加子菜單。 * * @param menus 菜單列表,包含所有菜單項(xiàng)。 * @return 包含所有頂級菜單的列表,其中每個頂級菜單均已包含其所有子菜單。 */ List<Menu> topLevelMenus = menus.stream() // 使用流處理menus集合 .filter(menu -> menu.getParentId() == 0 || menus.stream().noneMatch(other -> other.getId().equals(menu.getParentId()))) // 篩選條件:父菜單ID為0或不存在對應(yīng)父菜單的菜單項(xiàng) .peek(menu -> menu.setChildren(getChildren(menu, menus))) // 為每個頂級菜單設(shè)置子菜單 .collect(Collectors.toList()); // 將篩選后的頂級菜單集合轉(zhuǎn)換為List(Menu)類型 }
3. 輔助方法——獲取指定菜單的所有子菜單
/** * 獲取指定菜單的所有子菜單。 * * @param menu 指定的菜單對象,我們要查找它的子菜單。 * @param menus 所有菜單的列表,從中篩選出子菜單。 * @return 返回一個包含指定菜單所有子菜單的列表。這個列表中的每個菜單對象都可能包含它們自己的子菜單列表。 */ private static List<Menu> getChildren(Menu menu, List<Menu> menus) { // 使用流對菜單列表進(jìn)行處理,篩選出指定菜單的子菜單 return menus.stream() .filter(child -> child.getParentId().equals(menu.getId())) // 篩選條件:菜單的父菜單ID與指定菜單ID匹配 .peek(child -> child.setChildren(getChildren(child, menus))) // 遞歸設(shè)置每個子菜單的子菜單列表 .collect(Collectors.toList()); // 收集結(jié)果,生成列表 }
4. 示例數(shù)據(jù)生成方法 —— menusData()
private static List<Menu> menusData() { return Arrays.asList( new Menu(1L, "一級菜單1", 0L, null), new Menu(2L, "二級菜單1", 1L, null), new Menu(3L, "三級菜單1", 2L, null), new Menu(4L, "一級菜單2", 0L, null), new Menu(5L, "二級菜單2", 4L, null), new Menu(6L, "一級菜單3", 0L, null) ); }
5.完整代碼,以及演示(TreeExample.java)
package com.tenement.auto; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class TreeExample { @Data @NoArgsConstructor @AllArgsConstructor static class Menu { private Long id; private String name; private Long parentId; private List<Menu> children; } public static void main(String[] args) { List<Menu> menus = menusData(); /** * 從菜單列表中篩選出頂級菜單,并為其添加子菜單。 * * @param menus 菜單列表,包含所有菜單項(xiàng)。 * @return 包含所有頂級菜單的列表,其中每個頂級菜單均已包含其所有子菜單。 */ List<Menu> topLevelMenus = menus.stream() // 使用流處理menus集合 .filter(menu -> menu.getParentId() == 0 || menus.stream().noneMatch(other -> other.getId().equals(menu.getParentId()))) // 篩選條件:父菜單ID為0或不存在對應(yīng)父菜單的菜單項(xiàng) .peek(menu -> menu.setChildren(getChildren(menu, menus))) // 為每個頂級菜單設(shè)置子菜單 .collect(Collectors.toList()); // 將篩選后的頂級菜單集合轉(zhuǎn)換為List(Menu)類型 } /** * 獲取指定菜單的所有子菜單。 * * @param menu 指定的菜單對象,我們要查找它的子菜單。 * @param menus 所有菜單的列表,從中篩選出子菜單。 * @return 返回一個包含指定菜單所有子菜單的列表。這個列表中的每個菜單對象都可能包含它們自己的子菜單列表。 */ private static List<Menu> getChildren(Menu menu, List<Menu> menus) { // 使用流對菜單列表進(jìn)行處理,篩選出指定菜單的子菜單 return menus.stream() .filter(child -> child.getParentId().equals(menu.getId())) // 篩選條件:菜單的父菜單ID與指定菜單ID匹配 .peek(child -> child.setChildren(getChildren(child, menus))) // 遞歸設(shè)置每個子菜單的子菜單列表 .collect(Collectors.toList()); // 收集結(jié)果,生成列表 } private static List<Menu> menusData() { return Arrays.asList( new Menu(1L, "一級菜單1", 0L,null), new Menu(2L, "二級菜單1", 1L,null), new Menu(3L, "三級菜單1", 2L,null), new Menu(4L, "一級菜單2", 0L,null), new Menu(5L, "二級菜單2", 4L,null), new Menu(6L, "一級菜單3", 0L,null) ); } }
總結(jié)
該案例展示了如何利用Java 的Stream API對菜單數(shù)據(jù)進(jìn)行處理,首先篩選出頂級菜單項(xiàng),并通過遞歸方式為其添加子菜單。最后,得到了一個完整的樹形菜單結(jié)構(gòu)。
到此這篇關(guān)于詳解如何使用Java流API構(gòu)建樹形結(jié)構(gòu)數(shù)據(jù)的文章就介紹到這了,更多相關(guān)Java流構(gòu)建樹形結(jié)構(gòu)數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring cloud oauth2 feign 遇到的坑及解決
這篇文章主要介紹了spring cloud oauth2 feign 遇到的坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03解決SpringBoot webSocket 資源無法加載、tomcat啟動報錯的問題
這篇文章主要介紹了解決SpringBoot webSocket 資源無法加載、tomcat啟動報錯的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11BMIDE環(huán)境導(dǎo)入項(xiàng)目報編碼錯誤解決方案
這篇文章主要介紹了BMIDE環(huán)境導(dǎo)入項(xiàng)目報編碼錯誤解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10MyBatis-Plus?條件查詢器的實(shí)現(xiàn)
本文主要介紹了MyBatis-Plus?條件查詢器的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07Java LinkedHashMap 底層實(shí)現(xiàn)原理分析
LinkedHashMap繼承自HashMap實(shí)現(xiàn)了Map接口?;緦?shí)現(xiàn)同HashMap一樣,不同之處在于LinkedHashMap保證了迭代的有序性。其內(nèi)部維護(hù)了一個雙向鏈表,解決了 HashMap不能隨時保持遍歷順序和插入順序一致的問題。2021-05-05