天天看点

通过递归构造树背景实体结构代码

递归构树

  • 背景
  • 实体结构
  • 代码

背景

构造一棵树,再通过json返回给前端展示是我们经常需要遇到的功能。在这里总结一下通过递归功能构造树,结合着stream,将代码变得简洁易懂。

实体结构

通常的实体类型树结构,为List< List<…> >,最外边为root节点,里边为子子孙孙节点。其中还需要有一个关联关系,子节点可以通过parentId关联父节点。实体类例子如下:

这是一个类名为SlogPolicy的树结构,其中主要用到的属性如下:

通过递归构造树背景实体结构代码

所属层级和路径如有需要可以加上,并不影响树的构造

通过递归构造树背景实体结构代码
通过递归构造树背景实体结构代码

代码

因为比较简单、代码就直接贴图了。但是思路会在下方指出

通过递归构造树背景实体结构代码

上图有三步:

  1. 从数据库中获取到所有需要展示的节点,相当于直接缓存到内存中;
  2. 通过filter方法过滤出父节点,依据为parentId为0;
  3. 通过peek方法在每一个父节点下set子节点。

之后进入获取子节点的递归方法getChildren(),如下:

参数说明:第一个参数就是当前父节点、第二个参数为上述步骤1查询出的数据

通过递归构造树背景实体结构代码
  1. 通过stream对所有数据进行操作
  2. 通过filter方法过滤出所属父节点,依据为子节点的parentId为父节点的id;
  3. 通过peek方法在每一个子节点下再set孙节点。如有需要也可以通过sorted方法对生成的列表排序
递归出口:可以想到,当子节点下再找不到下一级的子节点了,那么这个root节点下的递归构造就完成了,便可回溯。也就是通过filter方法过滤出的数据为空了。

上诉步骤完成后,树结构就构造完成。可以看到通过stream流方式很方便。

这样的方法还可以想到优化的点,因为每次要把所有查到的数据作为参数代入到递归方法中,之后通过stream处理。数据量大的情况下会耗费一定的性能。因此也可以通过:

1、不一次性查询到所有数据缓存到内存中,而是先查到所有父节点数据,再在递归过程中查询到其下的子节点数据。(这样是会照成请求数据库I/O次数较多)。

2、可以将已经set的数据进行清理,这样数据量会逐级递减。

上诉stream流中使用到了peek方法,说明一下与map的区别:

主要区别为:peek为消费型接口,调用peek方法后, 流还在。

map方法是函数型接口。调用map方法后,流已经被消费。

peek对一个对象进行操作的时候,对象不变,但是可以改变对象里面的值

map方法接收一个Function作为入参. Function是有返回值的, 这就表示map对Stream中的元素的操作结果都会返回到Stream中去

四种函数式接口:

通过递归构造树背景实体结构代码