Java利用遞歸實(shí)現(xiàn)樹形結(jié)構(gòu)的工具類
需求描述
有時候,我們的數(shù)據(jù)是帶有層級的,比如常見的省市區(qū)三級聯(lián)動,就是一層套著一層,如下圖:
而我們在數(shù)據(jù)庫存放數(shù)據(jù)的時候,往往是列表形式的,如下圖:
那么當(dāng)我們從數(shù)據(jù)庫查詢出來,返回給前端的時候,前端又需要給出樹形層級的時候,這個時候可能就需要遞歸處理為樹形結(jié)構(gòu)了,因此下面這個工具或許就可以用得上了。
使用示例
我們按照上面定義一個Place對象,打上工具注解:
- @TreeKey 標(biāo)識唯一
- @TreeParentKey 標(biāo)識父節(jié)點(diǎn)標(biāo)識
- @TreeChildren 標(biāo)識子孫節(jié)點(diǎn)集合
@Data @Data public class Place { @TreeKey private String id; @TreeParentKey private String parentId; private String name; @TreeChildren private List<Place> children; public Place(String id, String name, String parentId) { this.id = id; this.name = name; this.parentId = parentId; } }
測試:
public class Test { public static void main(String[] args) { List<Place> places = new ArrayList<>(); places.add(new Place("510000", "四川省", "0")); places.add(new Place("510100", "成都市", "510000")); places.add(new Place("510107", "武侯區(qū)", "510100")); places.add(new Place("510116", "雙流區(qū)", "510100")); places.add(new Place("511600", "廣安市", "510000")); places.add(new Place("511603", "前鋒區(qū)", "511600")); places.add(new Place("511621", "岳池縣", "511600")); List<Place> treeList = TreeUtils.getTree(places, "0"); System.out.println(JSON.toJSONString(treeList)); } }
最終效果:
工具代碼
@TreeKey
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface TreeKey { }
@TreeParentKey
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface TreeParentKey { }
@TreeChildren
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface TreeChildren { }
@TreeUtils
package com.csd.utils.tree; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; /** * 遞歸求樹形工具類 * * @author Yuanqiang.Zhang * @since 2023/3/8 */ public class TreeUtils { /** * 集合轉(zhuǎn)化為樹形 * * @param list 集合 * @param highestParentKey 最高層父節(jié)點(diǎn)值 * @param <T> 泛型 * @return 樹形 */ public static <T> List<T> getTree(List<T> list, Object highestParentKey) { if (Objects.isNull(list) || list.isEmpty()) { return Collections.emptyList(); } Field key = null; Field parentKey = null; Field children = null; Field[] fields = list.get(0).getClass().getDeclaredFields(); for (Field field : fields) { if (Objects.isNull(key)) { TreeKey treeKey = field.getAnnotation(TreeKey.class); if (Objects.nonNull(treeKey)) { key = field; continue; } } if (Objects.isNull(parentKey)) { TreeParentKey treeParentKey = field.getAnnotation(TreeParentKey.class); if (Objects.nonNull(treeParentKey)) { parentKey = field; continue; } } if (Objects.isNull(children)) { TreeChildren treeChildren = field.getAnnotation(TreeChildren.class); if (Objects.nonNull(treeChildren)) { children = field; continue; } } } if (Objects.isNull(key) || Objects.isNull(parentKey) || Objects.isNull(children)) { return Collections.emptyList(); } key.setAccessible(true); parentKey.setAccessible(true); children.setAccessible(true); // 獲取最高層數(shù)據(jù) List<T> highs = new ArrayList<>(); try { for (T t : list) { Object pk = parentKey.get(t); if (getString(pk).equals(getString(highestParentKey))) { highs.add(t); } } // 獲取最高層子孫節(jié)點(diǎn) for (T t : highs) { setChildren(list, t, key, parentKey, children); } } catch (IllegalAccessException e) { e.printStackTrace(); } return highs; } /** * 獲取子孫節(jié)點(diǎn) * * @param list 集合 * @param parent 父節(jié)點(diǎn)對象 * @param key 唯一屬性 * @param parentKey 父唯一屬性 * @param children 節(jié)點(diǎn) * @param <T> 泛型 * @return 帶有子孫集合的父節(jié)點(diǎn)對象 * @throws IllegalAccessException */ private static <T> T setChildren(List<T> list, T parent, Field key, Field parentKey, Field children) throws IllegalAccessException { Object k = key.get(parent); List<T> tempList = new ArrayList<>(); for (T t : list) { Object pk = parentKey.get(t); if (getString(k).equals(getString(pk))) { tempList.add(setChildren(list, t, key, parentKey, children)); } } children.set(parent, tempList); return parent; } /** * 獲取字符串 * * @param o 值 * @return 字符串 */ private static String getString(Object o) { return Objects.isNull(o) ? "" : o.toString(); } }
以上就是Java利用遞歸實(shí)現(xiàn)樹形結(jié)構(gòu)的工具類的詳細(xì)內(nèi)容,更多關(guān)于Java樹形結(jié)構(gòu)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java如何把數(shù)組轉(zhuǎn)換為ArrayList
這篇文章主要介紹了Java如何把數(shù)組轉(zhuǎn)換為ArrayList,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-01-01Java使用BigDecimal精確運(yùn)算浮點(diǎn)數(shù)
這篇文章主要介紹了Java使用BigDecimal精確運(yùn)算浮點(diǎn)數(shù),幫助大家更好的處理浮點(diǎn)數(shù)數(shù)據(jù),感興趣的朋友可以了解下2020-10-10java如何實(shí)現(xiàn)多線程的順序執(zhí)行
多線程是java的一種重要技術(shù),但是多線程的運(yùn)行是沒有絕對的順序的,那么java如何實(shí)現(xiàn)多線程的順序執(zhí)行,下面就一起來了解一下2021-05-05Nacos服務(wù)實(shí)例的權(quán)重設(shè)置方式(以及設(shè)置為0時的作用與場景)
這篇文章主要介紹了Nacos服務(wù)實(shí)例的權(quán)重設(shè)置方式(以及設(shè)置為0時的作用與場景),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07JAVA LinkedList和ArrayList的使用及性能分析
JAVA LinkedList和ArrayList的使用及性能分析,這篇文章也是以JAVA List的總結(jié)。2013-11-11Session過期后自動跳轉(zhuǎn)到登錄頁面的實(shí)例代碼
這篇文章主要介紹了Session過期后自動跳轉(zhuǎn)到登錄頁面實(shí)例代碼,非常不錯具有參考借鑒價值,需要的朋友可以參考下2016-06-06