jdk8妙用——节点list生成树

问题

场景:许多同学都遇到过将nodeLsit生成nodeTree的情况(节点列表拼接成树),但是经常是遇到一个新节点(新的类)就重写一个 listTotree 方法。代码逻辑一致,致冗余了。

解决

有两种方法减少此冗余,如下

方法一

1、提供一个node接口
2、节点对象实现此node
3、实现node对象的 toTree方法
代码大致如下:


 //公共的节点接口
 public interface MyNode{
        //获取节点id
        Object getNodeId();

        //获取节点父id
        Object getNodeParentId();

        //获取节点子列表
        List<? extends MyNode> getNodeChildren();

        //设置子
        void setNodeChildren(List nodes);

        //获取节点序号
        Comparable getNodeOrder();
    }

	//某对象
    public class Bean implements MyNode{
        Integer id;
        Integer pId;
        Integer order;
        List<Bean> son;
        //下列为业务信息
        String info;

        @Override
        public Object getNodeId() {
            return this.id;
        }

        @Override
        public Object getNodeParentId() {
            return this.pId;
        }

        @Override
        public List<? extends MyNode> getNodeChildren() {
            return this.son;
        }

        @Override
        public Comparable getNodeOrder() {
            return this.order;
        }

        @Override
        public void setNodeChildren(List nodes) {
            this.son = nodes;
        }
    }

	//实现node方法
    public List list2Tree(List<? extends MyNode> nodes){
        List<Node> res = new ArrayList<>();
        //TODO nodes 转化成树 res
        
        return res;
    }

	//测试
    @Test
    public void test2Tree(){
        List<Bean> nodes = null;
        //TODO 初始化nodes

        List<Bean> list = list2Tree(nodes);
    }

方法二

利用jdk8的特性,进行抽象
估计说的太抽象大家不理解,方法二我写了详细代码,并提供测试结果

方法二代码
/** 工具代码 */
package com.xxx.util;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Function;

public class ListToTreeUtil {

	// list转树,不排序
    public static <T> List<T> list2Tree(List<T> list,
                                        Function<T, Serializable> getId,
                                        Function<T, Serializable> getParentId,
                                        Function<T, List<T>> getChildren,
                                        BiConsumer<T, List<T>> setChildren,
                                        Object root){
        return list2Tree(list, getId, getParentId, getChildren, setChildren, root, null);
    }

	// list转树,可排序
    public static <T> List<T> list2Tree(List<T> list,
                                        Function<T, Serializable> getId,
                                        Function<T, Serializable> getParentId,
                                        Function<T, List<T>> getChildren,
                                        BiConsumer<T, List<T>> setChildren,
                                        Object root,
                                        Function<T, Comparable> getOrder){
        List<T> treeList = new ArrayList<>();
        for(T tree : list){
            //check root
            if(objEquals(root, getParentId.apply(tree))){
                treeList.add(tree);
            }
            //find tree's Children
            for(T treeNode : list){
                if(objEquals(getId.apply(tree), getParentId.apply(treeNode))){
                    if(getChildren.apply(tree) == null){
                        setChildren.accept(tree, new ArrayList<T>());
                    }
                    getChildren.apply(tree).add(treeNode);
                }
            }
            if( getOrder != null){
                List<T> childList = getChildren.apply(tree);
                if( childList != null && childList.size() > 1){
                    List<T> sortList = getSortList(childList, getOrder);
                    setChildren.accept(tree, sortList);
                }
            }
        }
        return treeList;
    }

	//对比对象是否相等
    public static boolean objEquals(Object a, Object b){
        if(a == null)
            return b == null;
        return a.equals(b);
    }

	//list排序
    public static <T> List<T> getSortList(List<T> list,Function<T, Comparable> getOrder){
        List<T> sortList = new ArrayList<>();
        List<T> nullOrderList = new ArrayList<>();
        for(T item : list){
            if(null == getOrder.apply(item)){
                nullOrderList.add(item);
            }else {
                sortList.add(item);
            }
        }
        sortList.sort((a,b) -> getOrder.apply(a).compareTo(getOrder.apply(b)));
        sortList.addAll(nullOrderList);
        return sortList;
    }
}


方法二测试
	/** bean */
	//Node对象
	@Data
    @AllArgsConstructor
    class Node{
        Integer id;
        Integer pId;
        Integer order;
        List<Node> son;
    }

	//Node2对象
    @Data
    @AllArgsConstructor
    class Node2{
        String id2;
        String pId2;
        String order2;
        List<Node2> son2;
    }

/** 方法二 测试代码 */

    @Test
    public void tree2list2(){
        //测试Node对象,且排序
        List<Node> list = Arrays.asList(new Node(0, null, null, null),
                new Node(1, 0, -1, null),
                new Node(2, 0, -2, null),
                new Node(11, 1,-11, null),
                new Node(12, 1,-12, null),
                new Node(21, 2,-21, null),
                new Node(22, 2,-22, null),
                new Node(31, 3,-31, null)
        );
        List<Node> tree = ListToTreeUtil.list2Tree(list, Node::getId, Node::getPId, Node::getSon, Node::setSon, null, Node::getOrder);
        System.out.println(JSON.toJSONString(tree));


        //测试Node2对象,但选择不排序
        List<Node2> listNode2 = Arrays.asList(
                new Node2("0" , null, null, null),
                new Node2("1" , "0", "a1", null),
                new Node2("2" , "0", "a", null),
                new Node2("11", "1", "b1", null),
                new Node2("12", "1", "b", null),
                new Node2("21", "2", "c1", null),
                new Node2("22", "2", "c", null),
                new Node2("31", "3", "d", null)
        );
        List<Node2> treeNode2 = ListToTreeUtil.list2Tree(listNode2, Node2::getId2, Node2::getPId2, Node2::getSon2, Node2::setSon2, null, null);
        System.out.println(JSON.toJSONString(treeNode2));

    }
方法二测试结果
//执行结果如下
[{"id":0,"son":[{"id":2,"order":-2,"pId":0,"son":[{"id":22,"order":-22,"pId":2},{"id":21,"order":-21,"pId":2}]},{"id":1,"order":-1,"pId":0,"son":[{"id":12,"order":-12,"pId":1},{"id":11,"order":-11,"pId":1}]}]}]
[{"id2":"0","son2":[{"id2":"1","order2":"a1","pId2":"0","son2":[{"id2":"11","order2":"b1","pId2":"1"},{"id2":"12","order2":"b","pId2":"1"}]},{"id2":"2","order2":"a","pId2":"0","son2":[{"id2":"21","order2":"c1","pId2":"2"},{"id2":"22","order2":"c","pId2":"2"}]}]}]

Process finished with exit code 0

node树的可视化如下
node的可视化如下

node2树的可视化如下node2拼成树的结果

区别

  1. 方法一(节点接口)

    优点:一次实现多次调用;便于理解。
    缺点:有一定的代码侵入。

  2. 方法二(jdk8特性)

    优点:无代码侵入。
    缺点:使用有一定难度,初学者不好理解。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值