add method for Tree

This commit is contained in:
Looly 2021-11-11 22:57:07 +08:00
parent bb1e4ba76a
commit ab1d8e84e4
4 changed files with 137 additions and 5 deletions

View File

@ -10,6 +10,7 @@
* 【http 】 增加HttpResourceissue#1943@Github
* 【http 】 增加BytesBody、FormUrlEncodedBody
* 【cron 】 TaskTable.remove增加返回值issue#I4HX3B@Gitee
* 【core 】 Tree增加filter、filterNew、cloneTree、hasChild方法issue#I4HFC6@Gitee
### 🐞Bug修复
* 【core 】 修复FileResource构造fileName参数无效问题issue#1942@Github

View File

@ -2,6 +2,7 @@ package cn.hutool.core.lang.tree;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Filter;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.ObjectUtil;
@ -175,6 +176,16 @@ import java.util.function.Consumer;
return (List<Tree<T>>) this.get(treeNodeConfig.getChildrenKey());
}
/**
* 是否有子节点无子节点则此为叶子节点
*
* @return 是否有子节点
* @since 5.7.17
*/
public boolean hasChild() {
return CollUtil.isNotEmpty(getChildren());
}
/**
* 递归树并处理子树下的节点
*
@ -189,13 +200,62 @@ import java.util.function.Consumer;
}
}
/**
* 递归过滤并生成新的树<br>
* 通过{@link Filter}指定的过滤规则本节点或子节点满足过滤条件则保留当前节点否则抛弃节点及其子节点
*
* @param filter 节点过滤规则函数只需处理本级节点本身即可
* @return 过滤后的节点{@code null} 表示不满足过滤要求丢弃之
* @see #filter(Filter)
* @since 5.7.17
*/
public Tree<T> filterNew(Filter<Tree<T>> filter) {
return cloneTree().filter(filter);
}
/**
* 递归过滤当前树注意此方法会修改当前树<br>
* 通过{@link Filter}指定的过滤规则本节点或子节点满足过滤条件则保留当前节点否则抛弃节点及其子节点
*
* @param filter 节点过滤规则函数只需处理本级节点本身即可
* @return 过滤后的节点{@code null} 表示不满足过滤要求丢弃之
* @see #filterNew(Filter)
* @since 5.7.17
*/
public Tree<T> filter(Filter<Tree<T>> filter) {
final List<Tree<T>> children = getChildren();
if (CollUtil.isNotEmpty(children)) {
// 递归过滤子节点
final List<Tree<T>> filteredChildren = new ArrayList<>(children.size());
Tree<T> filteredChild;
for (Tree<T> child : children) {
filteredChild = child.filter(filter);
if (null != filteredChild) {
filteredChildren.add(filteredChild);
}
}
if(CollUtil.isNotEmpty(filteredChildren)){
// 子节点有符合过滤条件的节点则本节点保留
return this.setChildren(filteredChildren);
} else {
this.setChildren(null);
}
}
// 子节点都不符合过滤条件检查本节点
return filter.accept(this) ? this : null;
}
/**
* 设置子节点设置后会覆盖所有原有子节点
*
* @param children 子节点列表
* @param children 子节点列表如果为{@code null}表示移除子节点
* @return this
*/
public Tree<T> setChildren(List<Tree<T>> children) {
if(null == children){
this.remove(treeNodeConfig.getChildrenKey());
}
this.put(treeNodeConfig.getChildrenKey(), children);
return this;
}
@ -241,6 +301,34 @@ import java.util.function.Consumer;
return stringWriter.toString();
}
/**
* 递归克隆当前节点即克隆整个树保留字段值<br>
* 注意此方法只会克隆节点节点属性如果是引用类型不会克隆
*
* @return 新的节点
* @since 5.7.17
*/
public Tree<T> cloneTree() {
final Tree<T> result = ObjectUtil.clone(this);
result.setChildren(cloneChildren());
return result;
}
/**
* 递归复制子节点
*
* @return 新的子节点列表
*/
private List<Tree<T>> cloneChildren() {
final List<Tree<T>> children = getChildren();
if (null == children) {
return null;
}
final List<Tree<T>> newChildren = new ArrayList<>(children.size());
children.forEach((t) -> newChildren.add(t.cloneTree()));
return newChildren;
}
/**
* 打印
*

View File

@ -76,4 +76,48 @@ public class TreeTest {
Assert .assertEquals(7, ids.size());
}
@Test
public void cloneTreeTest(){
final Tree<String> tree = TreeUtil.buildSingle(nodeList, "0");
final Tree<String> cloneTree = tree.cloneTree();
List<String> ids = new ArrayList<>();
cloneTree.walk((tr)-> ids.add(tr.getId()));
Assert .assertEquals(7, ids.size());
}
@Test
public void filterTest(){
// 经过过滤丢掉"用户添加"节点
final Tree<String> tree = TreeUtil.buildSingle(nodeList, "0");
tree.filter((t)->{
final CharSequence name = t.getName();
return null != name && name.toString().contains("管理");
});
List<String> ids = new ArrayList<>();
tree.walk((tr)-> ids.add(tr.getId()));
Assert .assertEquals(6, ids.size());
}
@Test
public void filterNewTest(){
final Tree<String> tree = TreeUtil.buildSingle(nodeList, "0");
// 经过过滤生成新的树
Tree<String> newTree = tree.filterNew((t)->{
final CharSequence name = t.getName();
return null != name && name.toString().contains("管理");
});
List<String> ids = new ArrayList<>();
newTree.walk((tr)-> ids.add(tr.getId()));
Assert .assertEquals(6, ids.size());
List<String> ids2 = new ArrayList<>();
tree.walk((tr)-> ids2.add(tr.getId()));
Assert .assertEquals(7, ids2.size());
}
}

View File

@ -68,7 +68,6 @@ public class TimingWheel {
* @param consumer 任务处理器
*/
public TimingWheel(long tickMs, int wheelSize, long currentTime, Consumer<TimerTaskList> consumer) {
this.currentTime = currentTime;
this.tickMs = tickMs;
this.wheelSize = wheelSize;
this.interval = tickMs * wheelSize;