lastRet;
+ private E currentElement;
+
+ Itr() {
+ fullyLock();
+ try {
+ current = head.next;
+ if (current != null)
+ currentElement = current.item;
+ } finally {
+ fullyUnlock();
+ }
+ }
+
+ public boolean hasNext() {
+ return current != null;
+ }
+
+ /**
+ * Returns the next live successor of p, or null if no such.
+ *
+ * Unlike other traversal methods, iterators need to handle both:
+ * - dequeued nodes (p.next == p)
+ * - (possibly multiple) interior removed nodes (p.item == null)
+ */
+ private Node nextNode(Node p) {
+ for (; ; ) {
+ Node s = p.next;
+ if (s == p)
+ return head.next;
+ if (s == null || s.item != null)
+ return s;
+ p = s;
+ }
+ }
+
+ public E next() {
+ fullyLock();
+ try {
+ if (current == null)
+ throw new NoSuchElementException();
+ E x = currentElement;
+ lastRet = current;
+ current = nextNode(current);
+ currentElement = (current == null) ? null : current.item;
+ return x;
+ } finally {
+ fullyUnlock();
+ }
+ }
+
+ public void remove() {
+ if (lastRet == null)
+ throw new IllegalStateException();
+ fullyLock();
+ try {
+ Node node = lastRet;
+ lastRet = null;
+ boolean overBorder = false;
+ for (Node trail = head, p = trail.next;
+ p != null;
+ trail = p, p = p.next) {
+ if (!overBorder) overBorder = trail == border;
+ if (p == node) {
+ unlink(p, trail, overBorder);
+ break;
+ }
+ }
+ } finally {
+ fullyUnlock();
+ }
+ }
+ }
+}
diff --git a/njzscloud-common/njzscloud-common-core/src/main/java/com/njzscloud/common/core/tree/Tree.java b/njzscloud-common/njzscloud-common-core/src/main/java/com/njzscloud/common/core/tree/Tree.java
new file mode 100644
index 0000000..547ab68
--- /dev/null
+++ b/njzscloud-common/njzscloud-common-core/src/main/java/com/njzscloud/common/core/tree/Tree.java
@@ -0,0 +1,137 @@
+package com.njzscloud.common.core.tree;
+
+
+import cn.hutool.core.collection.CollUtil;
+import com.njzscloud.common.core.utils.GroupUtil;
+
+import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * 树型结构工具
+ */
+public class Tree {
+
+ /**
+ * 创建树形数据(倒序)
+ *
+ * @param src 源集合
+ * @param rootId 根节点 ID
+ * @param 节点 ID 类型
+ * @return List<? extends TreeNode<T>>
+ */
+ public static List extends TreeNode> listToTreeDesc(List extends TreeNode> src, T rootId) {
+ return listToTree(src.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList()), TreeNode::getId, TreeNode::getPid, TreeNode::setChildren, rootId, true);
+ }
+
+ /**
+ * 创建树形数据(正序)
+ *
+ * @param src 源集合
+ * @param rootId 根节点 ID
+ * @param 节点 ID 类型
+ * @return List<? extends TreeNode<T>>
+ */
+ public static List extends TreeNode> listToTreeAsc(List extends TreeNode> src, T rootId) {
+ return listToTree(src.stream().sorted().collect(Collectors.toList()), TreeNode::getId, TreeNode::getPid, TreeNode::setChildren, rootId, false);
+ }
+
+ /**
+ * 创建树形数据(排序)
+ *
+ * @param src 源集合
+ * @param idFn id 提供函数
+ * @param pidFn pid 提供函数
+ * @param setChildrenFn 子节点设置函数
+ * @param rootId 根节点 ID
+ * @param reverse 是否倒序
+ * @param 源集合元素类型
+ * @param 节点 ID 类型
+ * @return List<M>
+ */
+ public static , T> List listToTree(List src, Function idFn, Function pidFn, BiConsumer> setChildrenFn, T rootId, boolean reverse) {
+ if (CollUtil.isEmpty(src)) return Collections.emptyList();
+ if (reverse) {
+ src = src
+ .stream()
+ .sorted(Comparator.reverseOrder())
+ .collect(Collectors.toList());
+ }
+
+ Map> pid_treeNode_map = GroupUtil.k_a(src, pidFn);
+
+ for (M m : src) {
+ setChildrenFn.accept(m, pid_treeNode_map.get(idFn.apply(m)));
+ }
+ return CollUtil.emptyIfNull(pid_treeNode_map.get(rootId));
+ }
+
+ /**
+ * 创建树形数据(不排序)
+ *
+ * @param src 源集合
+ * @param idFn id 提供函数
+ * @param pidFn pid 提供函数
+ * @param setChildrenFn 子节点设置函数
+ * @param rootId 根节点 ID
+ * @param 源集合元素类型
+ * @param 节点 ID 类型
+ * @return List<M>
+ */
+ public static List listToTree(List src, Function idFn, Function pidFn, BiConsumer> setChildrenFn, T rootId) {
+ if (CollUtil.isEmpty(src)) return Collections.emptyList();
+
+ Map> pid_treeNode_map = GroupUtil.k_a(src, pidFn);
+
+ for (M m : src) {
+ setChildrenFn.accept(m, pid_treeNode_map.get(idFn.apply(m)));
+ }
+ return CollUtil.emptyIfNull(pid_treeNode_map.get(rootId));
+ }
+
+ /**
+ * 扁平化树
+ *
+ * @param src 源集合 树形结构
+ * @param getChildrenFn 子节点获取函数
+ * @param convert 转换函数, 源集合 元素 -> 结果集合 元素
+ * @param 源集合 元素类型
+ * @param 结果集合 元素类型
+ * @return List<D>
+ */
+ public static List treeToList(List src, Function> getChildrenFn, Function convert) {
+ List dest;
+ if (CollUtil.isNotEmpty(src)) {
+ dest = new ArrayList<>();
+ treeToList(src, dest, getChildrenFn, convert);
+ } else {
+ dest = Collections.emptyList();
+ }
+ return dest;
+ }
+
+ /**
+ * 扁平化树
+ *
+ * @param src 源集合 树形结构
+ * @param dest 结果集合
+ * @param getChildrenFn 子节点获取函数
+ * @param convert 转换函数, 源集合 元素 -> 结果集合 元素
+ * @param 源集合 元素类型
+ * @param 结果集合 元素类型
+ */
+ public static void treeToList(List src, List dest, Function> getChildrenFn, Function convert) {
+ if (CollUtil.isNotEmpty(src)) {
+ for (S s : src) {
+ D d = convert.apply(s);
+ dest.add(d);
+ List children = getChildrenFn.apply(s);
+ if (CollUtil.isNotEmpty(children)) {
+ Tree.treeToList(children, dest, getChildrenFn, convert);
+ }
+ }
+ }
+ }
+}
diff --git a/njzscloud-common/njzscloud-common-core/src/main/java/com/njzscloud/common/core/tree/TreeNode.java b/njzscloud-common/njzscloud-common-core/src/main/java/com/njzscloud/common/core/tree/TreeNode.java
new file mode 100644
index 0000000..18faf02
--- /dev/null
+++ b/njzscloud-common/njzscloud-common-core/src/main/java/com/njzscloud/common/core/tree/TreeNode.java
@@ -0,0 +1,51 @@
+package com.njzscloud.common.core.tree;
+
+
+import java.util.List;
+
+/**
+ * 树结点
+ *
+ * @param Id 的数据类型
+ */
+public interface TreeNode extends Comparable> {
+ /**
+ * 节点 ID
+ *
+ * @return T id
+ */
+ T getId();
+
+ /**
+ * 节点 上级 ID
+ *
+ * @return T pid
+ */
+ T getPid();
+
+ /**
+ * 排序
+ *
+ * @return int
+ */
+ int getSort();
+
+ /**
+ * 子节点
+ *
+ * @return List<? extends TreeNode<T>>
+ */
+ List extends TreeNode> getChildren();
+
+ /**
+ * 设置子节点
+ *
+ * @param children 子节点
+ */
+ void setChildren(List extends TreeNode> children);
+
+ @Override
+ default int compareTo(TreeNode o) {
+ return this.getSort() - o.getSort();
+ }
+}
diff --git a/njzscloud-common/njzscloud-common-core/src/main/java/com/njzscloud/common/core/tuple/Tuple2.java b/njzscloud-common/njzscloud-common-core/src/main/java/com/njzscloud/common/core/tuple/Tuple2.java
new file mode 100644
index 0000000..c8ecd7e
--- /dev/null
+++ b/njzscloud-common/njzscloud-common-core/src/main/java/com/njzscloud/common/core/tuple/Tuple2.java
@@ -0,0 +1,118 @@
+package com.njzscloud.common.core.tuple;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 2 元组
+ *
+ * @param <_0>
+ * @param <_1>
+ */
+public class Tuple2<_0, _1> {
+
+ /**
+ * 元组大小
+ */
+ @JsonIgnore
+ public final int size = 2;
+ /**
+ * 第 0 个数据
+ */
+ @JsonIgnore
+ protected final _0 _0_;
+ /**
+ * 第 1 个数据
+ */
+ @JsonIgnore
+ protected final _1 _1_;
+
+ /**
+ * 构造方法
+ *
+ * @param _0_ 第 0 个数据
+ * @param _1_ 第 1 个数据
+ */
+ public Tuple2(_0 _0_, _1 _1_) {
+ this._0_ = _0_;
+ this._1_ = _1_;
+ }
+
+ /**
+ * 创建 Tuple2
+ *
+ * @param _0_ 第 0 个数据
+ * @param _1_ 第 1 个数据
+ * @return Tuple2<__0, __1>
+ */
+ public static <__0, __1> Tuple2<__0, __1> of(__0 _0_, __1 _1_) {
+ return new Tuple2<>(_0_, _1_);
+ }
+
+ /**
+ * 获取第 0 个数据
+ */
+ @JsonProperty("0")
+ public _0 get_0() {
+ return _0_;
+ }
+
+ /**
+ * 获取第 1 个数据
+ */
+ @JsonProperty("1")
+ public _1 get_1() {
+ return _1_;
+ }
+
+ /**
+ * 按索引获取数据
+ * 索引越界将返回 null
+ *
+ * @param index 索引
+ * @return T
+ */
+ @SuppressWarnings("unchecked")
+ public T get(int index) {
+ return switch (index) {
+ case 0 -> (T) this._0_;
+ case 1 -> (T) this._1_;
+ default -> null;
+ };
+ }
+
+ /**
+ * 转换成 List
+ *
+ * @return List<Object>
+ */
+ public List