Java数组转树(listToTree), 树转数组(treeToList)的正确姿势, 写成接口方式

Java数组转树(listToTree), 树转数组(treeToList)的正确姿势, 写成接口方式

直接上代码:
package cn.mandy.sysadmin.common.util;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

// MandyTree 实现 deepClone, 需要 Serializable
public interface MandyTree<T> extends Serializable {
    
    Long getParentId();
    void setParentId(Long parentId);
    Long getId();
    void setId(Long id);
    List<T> getChildren();
    void setChildren(List<T> children);

    //java8 接口支持默认实现了
    static <T extends MandyTree<T>> List<T> treeToList(List<T> tree) {
        List<T> nodes = new ArrayList<>();
        for (T node : tree) {
            T newNode = deepClone(node);
            newNode.setChildren(null);
            nodes.add(newNode);
            if (node.getChildren() != null && ! node.getChildren().isEmpty()) {
                nodes.addAll(treeToList(node.getChildren()));
            }
        }
        return nodes;
    }

    static <T extends MandyTree<T>> List<T> listToTree(List<T> nodes) {
        List<T> tree = new ArrayList<>();
        for (T node : nodes) {
            T parent;
            Long parentId = node.getParentId();
            parent = findParent(parentId, tree);
            if (null == parent){
                //T newNode;
                //tree.add(node);  有问题的代码,要用deepClone噢
                tree.add(deepClone(node));
            }else {
                if (parent.getChildren() == null) {
                    parent.setChildren(new ArrayList<>());
                }
                //parent.getChildren().add(node);
                parent.getChildren().add(deepClone(node));
            }
        }
        return tree;
    }

    static <T extends MandyTree<T>> T findParent(Long parentId, List<T> nodeList) {
        for (T it : nodeList) {
            if (it.getId().equals(parentId)){
                return it;
            }else if (null != it.getChildren()){
                T parentNode = findParent(parentId, it.getChildren());
                if (null != parentNode){
                    return parentNode;
                }
            }
        }
        //nodeList.forEach();
        return null;
    }

    //一定要深克隆, 不能用原来的入参中的引用, 否则, 你试试看 :)
    static <T extends MandyTree<T>> T deepClone(T src) {
        //static <T extends MandyTree<T>> T deepClone(T src) {
        T dest = null;
        try { // 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream);
            oos.writeObject(src);
            //将流序列化成对象
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream);
            dest = (T) ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return dest;
    }
}

使用方法:
MandyDepartment 是由 MyBatisGenerator 生成的 model, id, parentId 字段都定义为 BigInteger;
其它表也一样,遵守统一约定。否则就要自己写getter, setter去实现 MandyTree 中的接口函数了.
生成代码后, 类声明改一下,如下,
public class MandyDepartment implements MandyTree<MandyDepartment> {
    private List<MandyDepartment> children;

再用IDE自动生成 Getter, Setter;
然后就可以愉快地使用了。
List<MandyDepartment> tree = MandyTree.listToTree(list);

注意这里还有一个约束条件, 就是List中, 父节点要排在子节点前面。
通常这个约束还是比较好办的, 表中id自增,父节点记录比子节点记录先一步插入,select 时 order by id 一下就可以了。
这样做比起用 tree.getPid() == 0 判断, 把这些节点当根节点先加入tree 的那种方式,
优点是你可以只得到部份数据(不一定包括表中的全部数据), 只得到一部份分枝,也能组成树。

我还看到有的童鞋用sql 语句 select a.*, b.* from table_name a left join table_name b on a.id = b.parent_id 的方法,
我认为更是不那么好的办法了。

新年了,因为新型肺炎宅在家里,写下首篇博文。
如果您看到这里,一起再为那些不幸染上新型肺炎的国人祈祷吧。
还有,祝福所有的人安康幸福,雪融冰消会有时, 春暖花开在明天!

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值