...
 
Commits (5)
    https://gitcode.net/duanluan/ZUtil/-/commit/17b735d4223201ec4e66968d20182bab79814dce feat: BeanUtils 新增 deepClone(深克隆)方法和深克隆性能测试 2023-05-04T04:23:38+08:00 duanluan duanluan@outlook.com https://gitcode.net/duanluan/ZUtil/-/commit/354ad17edda9c9d0df12b1a53ab6212c6728b22b feat: 新增 TreeUtils 树工具类、生成树节点列表性能测试和覆盖率测试 2023-05-04T04:25:23+08:00 duanluan duanluan@outlook.com https://gitcode.net/duanluan/ZUtil/-/commit/91ef767fe4afba2e04b2922e4e48642bb6cdd405 style: 代码优化 2023-05-04T04:28:34+08:00 duanluan duanluan@outlook.com https://gitcode.net/duanluan/ZUtil/-/commit/4a1a3f7362de2965726fa62075f41be1e70b7949 style: 更新版本号 2023-05-04T04:36:15+08:00 duanluan duanluan@outlook.com https://gitcode.net/duanluan/ZUtil/-/commit/03803aea3873dd2c02a4a8b3354c194260b6e835 style: 完善注释 2023-05-05T20:28:46+08:00 duanluan duanluan@outlook.com
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
<dependency> <dependency>
<groupId>top.csaf</groupId> <groupId>top.csaf</groupId>
<artifactId>ZUtil</artifactId> <artifactId>ZUtil</artifactId>
<version>1.11.1</version> <version>1.12.0</version>
</dependency> </dependency>
``` ```
...@@ -43,9 +43,9 @@ ...@@ -43,9 +43,9 @@
```groovy ```groovy
// groovy // groovy
implementation 'top.csaf:ZUtil:1.11.1' implementation 'top.csaf:ZUtil:1.12.0'
// kotlin // kotlin
implementation("top.csaf:ZUtil:1.11.1") implementation("top.csaf:ZUtil:1.12.0")
``` ```
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<dependency> <dependency>
<groupId>top.csaf</groupId> <groupId>top.csaf</groupId>
<artifactId>ZUtil</artifactId> <artifactId>ZUtil</artifactId>
<version>1.11.1</version> <version>1.12.0</version>
</dependency> </dependency>
``` ```
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
```groovy ```groovy
// groovy // groovy
implementation 'top.csaf:ZUtil:1.11.1' implementation 'top.csaf:ZUtil:1.12.0'
// kotlin // kotlin
implementation("top.csaf:ZUtil:1.11.1") implementation("top.csaf:ZUtil:1.12.0")
``` ```
## 安装注意 ## 安装注意
...@@ -32,7 +32,7 @@ implementation("top.csaf:ZUtil:1.11.1") ...@@ -32,7 +32,7 @@ implementation("top.csaf:ZUtil:1.11.1")
<dependency> <dependency>
<groupId>top.csaf</groupId> <groupId>top.csaf</groupId>
<artifactId>ZUtil</artifactId> <artifactId>ZUtil</artifactId>
<version>1.11.1</version> <version>1.12.0</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
...@@ -65,7 +65,7 @@ implementation("top.csaf:ZUtil:1.11.1") ...@@ -65,7 +65,7 @@ implementation("top.csaf:ZUtil:1.11.1")
// groovy // groovy
dependencies { dependencies {
// 方式一:ZUtil 排除 slf4j // 方式一:ZUtil 排除 slf4j
implementation('top.csaf:ZUtil:1.11.1') { implementation('top.csaf:ZUtil:1.12.0') {
exclude group: 'org.slf4j', module: 'slf4j-api' exclude group: 'org.slf4j', module: 'slf4j-api'
exclude group: 'org.slf4j', module: 'slf4j-simple' exclude group: 'org.slf4j', module: 'slf4j-simple'
} }
...@@ -78,7 +78,7 @@ dependencies { ...@@ -78,7 +78,7 @@ dependencies {
// kotlin // kotlin
dependencies { dependencies {
// 方式一:ZUtil 排除 slf4j // 方式一:ZUtil 排除 slf4j
implementation("top.csaf:ZUtil:1.11.1") { implementation("top.csaf:ZUtil:1.12.0") {
exclude(group = "org.slf4j", module = "slf4j-api") exclude(group = "org.slf4j", module = "slf4j-api")
exclude(group = "org.slf4j", module = "slf4j-simple") exclude(group = "org.slf4j", module = "slf4j-simple")
} }
......
# 不兼容变更 # 不兼容变更
* 1.12.0
* `ClassUtils.isBasic`重命名为`isPrimitiveType`
* `BeanUtils`移至`bean`包下。
* `BeanUtils.FieldFunction`重命名为`PropertyFunction`并移至根包下。
* `BeanUtils.getFieldName(FieldFunction)`重命名为`getPropertyName(PropertyFunction)`
* 删除`BeanUtils.deepToMap`
* 1.11.0 * 1.11.0
* Group Id 由`top.zhogjianhao`重命名为`top.csaf` * Group Id 由`top.zhogjianhao`重命名为`top.csaf`
* 1.10.1 * 1.10.1
* `id.NanoIDUtils`重命名为`id.NanoIdUtils` * `id.NanoIDUtils`重命名为`NanoIdUtils`
* 1.9.2 * 1.9.2
* 删除`FileUtils.getClassRootPath` * 删除`FileUtils.getClassRootPath`
* 删除`FileUtils.getClassPath` * 删除`FileUtils.getClassPath`
......
{ {
"name": "zutil-docs", "name": "zutil-docs",
"version": "1.11.1", "version": "1.12.0",
"private": true, "private": true,
"scripts": { "scripts": {
"docusaurus": "docusaurus", "docusaurus": "docusaurus",
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<groupId>top.csaf</groupId> <groupId>top.csaf</groupId>
<artifactId>ZUtil</artifactId> <artifactId>ZUtil</artifactId>
<version>1.11.1</version> <version>1.12.0</version>
<name>ZUtil</name> <name>ZUtil</name>
<url>https://github.com/duanluan/ZUtil</url> <url>https://github.com/duanluan/ZUtil</url>
...@@ -130,7 +130,18 @@ ...@@ -130,7 +130,18 @@
<dependency> <dependency>
<groupId>org.yaml</groupId> <groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId> <artifactId>snakeyaml</artifactId>
<version>1.33</version> <version>2.0</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.4.6</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.6</version>
</dependency> </dependency>
...@@ -172,7 +183,7 @@ ...@@ -172,7 +183,7 @@
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>
<version>5.8.1</version> <version>5.8.11</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
...@@ -193,6 +204,54 @@ ...@@ -193,6 +204,54 @@
<!-- <version>31.1-jre</version>--> <!-- <version>31.1-jre</version>-->
<!-- <scope>test</scope>--> <!-- <scope>test</scope>-->
<!--</dependency>--> <!--</dependency>-->
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>5.5.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.wicketstuff</groupId>
<artifactId>wicketstuff-serializer-fast2</artifactId>
<version>9.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.66</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.8.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.8.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.dyuproject.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.dyuproject.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>3.3</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<build> <build>
...@@ -385,6 +444,11 @@ ...@@ -385,6 +444,11 @@
<name>Maven Central</name> <name>Maven Central</name>
<url>https://repo.maven.apache.org/maven2/</url> <url>https://repo.maven.apache.org/maven2/</url>
</repository> </repository>
<!-- jitpack -->
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories> </repositories>
<pluginRepositories> <pluginRepositories>
<pluginRepository> <pluginRepository>
......
...@@ -248,6 +248,7 @@ public final class ArrayUtils extends org.apache.commons.lang3.ArrayUtils { ...@@ -248,6 +248,7 @@ public final class ArrayUtils extends org.apache.commons.lang3.ArrayUtils {
* @param array 数组 * @param array 数组
* @param startIndex 开始下标 * @param startIndex 开始下标
* @param length 位数 * @param length 位数
* @param <T> 数组类型
* @return 数组 * @return 数组
*/ */
public static <T> T[] moveForward(@NonNull final T[] array, final int startIndex, final int length) { public static <T> T[] moveForward(@NonNull final T[] array, final int startIndex, final int length) {
......
...@@ -19,7 +19,7 @@ public class ClassUtils extends org.apache.commons.lang3.ClassUtils { ...@@ -19,7 +19,7 @@ public class ClassUtils extends org.apache.commons.lang3.ClassUtils {
throw new IllegalArgumentException("Classes: length should be greater than 0"); throw new IllegalArgumentException("Classes: length should be greater than 0");
} }
for (Class<?> clazz : classes) { for (Class<?> clazz : classes) {
if (!((Integer.class.equals(clazz)) || if (!(Integer.class.equals(clazz) ||
Long.class.equals(clazz) || Long.class.equals(clazz) ||
Double.class.equals(clazz) || Double.class.equals(clazz) ||
Float.class.equals(clazz) || Float.class.equals(clazz) ||
...@@ -48,7 +48,7 @@ public class ClassUtils extends org.apache.commons.lang3.ClassUtils { ...@@ -48,7 +48,7 @@ public class ClassUtils extends org.apache.commons.lang3.ClassUtils {
throw new IllegalArgumentException("Objects: length should be greater than 0"); throw new IllegalArgumentException("Objects: length should be greater than 0");
} }
for (Object object : objects) { for (Object object : objects) {
if (!((object instanceof Integer) || if (!(object instanceof Integer ||
object instanceof Long || object instanceof Long ||
object instanceof Double || object instanceof Double ||
object instanceof Float || object instanceof Float ||
......
package top.csaf.bean; package top.csaf.bean;
import com.alibaba.fastjson2.JSON;
import lombok.NonNull; import lombok.NonNull;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.beanutils.PropertyUtils;
...@@ -356,4 +357,30 @@ public class BeanUtils extends org.springframework.beans.BeanUtils { ...@@ -356,4 +357,30 @@ public class BeanUtils extends org.springframework.beans.BeanUtils {
} }
return targetList; return targetList;
} }
/**
* 深克隆
*
* @param source 源对象
* @param <T> 源对象类型
* @return 深克隆后的对象
*/
public static <T> T deepClone(T source) {
return (T) JSON.parseObject(JSON.toJSONString(source), source.getClass());
}
/**
* 深克隆
*
* @param source 源集合
* @param <T> 源集合元素类型
* @return 深克隆后的集合
*/
public static <T> List<T> deepClone(List<T> source) {
List<T> result = new ArrayList<>();
for (T t : source) {
result.add(deepClone(t));
}
return result;
}
} }
...@@ -97,7 +97,8 @@ public class FileUtils extends org.apache.commons.io.FileUtils { ...@@ -97,7 +97,8 @@ public class FileUtils extends org.apache.commons.io.FileUtils {
/** /**
* 获取 resources 目录下的文件输入流 * 获取 resources 目录下的文件输入流
* *
* @param path 文件路径 * @param clazz 类
* @param path 文件路径
* @return 文件输入流 * @return 文件输入流
*/ */
public static InputStream getResourceAsStream(@NonNull Class<?> clazz, @NonNull final String path) { public static InputStream getResourceAsStream(@NonNull Class<?> clazz, @NonNull final String path) {
......
...@@ -316,6 +316,7 @@ public class PinyinUtils { ...@@ -316,6 +316,7 @@ public class PinyinUtils {
/** /**
* 是否为多音字 * 是否为多音字
* *
* @param c 字符
* @return 是否为多音字 * @return 是否为多音字
*/ */
public static boolean isPolyphonicWord(final char c) { public static boolean isPolyphonicWord(final char c) {
......
package top.csaf.tree;
import lombok.Data;
import java.util.Comparator;
/**
* 树节点配置
*/
@Data
public class TreeConfig {
/**
* 是否排序
*/
private boolean isSort = false;
/**
* 排序规则,默认按照 ID 排序,null 值排在开始
*/
private Comparator<TreeNode> comparator;
/**
* 根节点的父级 ID,默认为 0, 0L, "0", null, "", 0d, 0f, (short) 0
* <p>
* 节点的父级 ID 满足这些值,则为顶级节点
*/
private Object[] rootParentIdValues = new Object[]{0, 0L, "0", null, "", 0d, 0f, (short) 0};
/**
* 父级 ID 有值,但不满足 {@link TreeConfig#rootParentIdValues} 中的值,而且查不到父级时,是否为顶级节点
*/
private boolean isRootByNullParent = false;
}
package top.csaf.tree;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
* 树节点
*/
@NoArgsConstructor
@Data
public class TreeNode implements Serializable {
/**
* ID
*/
private Object id;
/**
* 名称
*/
private String name;
/**
* 顺序
*/
private Integer order;
/**
* 父级 ID
*/
private Object parentId;
/**
* 子级列表
*/
private List<TreeNode> children;
public TreeNode(Object id, String name, Integer order, Object parentId) {
this.id = id;
this.name = name;
this.order = order;
this.parentId = parentId;
}
public TreeNode(Object id, String name, Integer order, TreeNode parent) {
this.id = id;
this.name = name;
this.order = order;
this.parentId = parent.getId();
}
}
package top.csaf.tree;
import top.csaf.ArrayUtils;
import top.csaf.bean.BeanUtils;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* 树工具类
*/
public class TreeUtils {
/**
* 构建树
* <p>
* 如果节点的父级 ID 满足 TreeConfig#getRootParentIdValues() 中的值,则为顶级节点
*
* @param treeNodes 树节点列表
* @return 树列表
*/
public static List<TreeNode> build(List<TreeNode> treeNodes) {
List<TreeNode> treeNodes1 = BeanUtils.deepClone(treeNodes);
// id 为 key,value 为自身存储到 Map 中
Map<String, TreeNode> treeNodeMap = new LinkedHashMap<>(treeNodes1.size());
for (TreeNode treeNode : treeNodes1) {
treeNodeMap.put(treeNode.getId().toString(), treeNode);
}
List<TreeNode> treeList = new ArrayList<>();
for (TreeNode treeNode : treeNodes1) {
// 根据当前节点的父级 ID 获取父级节点
TreeNode parent = treeNodeMap.get(treeNode.getParentId().toString());
// 如果满足顶级节点的条件
if (ArrayUtils.contains(new TreeConfig().getRootParentIdValues(), parent)) {
// 则为顶级节点
treeList.add(treeNode);
} else {
// 如果没有子节点列表,则创建列表
if (parent.getChildren() == null) {
parent.setChildren(new ArrayList<>());
}
// 将自身添加到父节点的子节点列表中
parent.getChildren().add(treeNode);
}
}
return treeList;
}
/**
* 构建树
*
* @param treeNodes 树节点列表
* @param treeConfig 树配置
* @return 树列表
*/
public static List<TreeNode> build(List<TreeNode> treeNodes, TreeConfig treeConfig) {
List<TreeNode> treeNodes1 = BeanUtils.deepClone(treeNodes);
// 排序
if (treeConfig.isSort()) {
if (treeConfig.getComparator() == null) {
throw new IllegalArgumentException("Comparator: when sort is true, comparator can not be null");
}
treeNodes1.sort(treeConfig.getComparator());
}
// id 为 key,value 为自身存储到 Map 中
Map<String, TreeNode> treeNodeMap = new LinkedHashMap<>(treeNodes1.size());
for (TreeNode treeNode : treeNodes1) {
treeNodeMap.put(treeNode.getId().toString(), treeNode);
}
List<TreeNode> treeList = new ArrayList<>();
for (TreeNode treeNode : treeNodes1) {
String parentId = treeNode.getParentId().toString();
// 如果父级 ID 满足顶级节点的值
if (ArrayUtils.contains(treeConfig.getRootParentIdValues(), parentId)) {
// 则为顶级节点
treeList.add(treeNode);
} else {
// 根据当前节点的父级 ID 获取父级节点
TreeNode parent = treeNodeMap.get(parentId);
// 如果没有父节点
if (treeConfig.isRootByNullParent() && parent == null) {
// 则为顶级节点
treeList.add(treeNode);
continue;
}
if (parent == null) {
// 丢弃该节点
continue;
}
// 如果没有子节点列表,则创建列表
if (parent.getChildren() == null) {
parent.setChildren(new ArrayList<>());
}
// 将自身添加到父节点的子节点列表中
parent.getChildren().add(treeNode);
}
}
return treeList;
}
}
package top.csaf.jmh.base.tree;
import org.junit.jupiter.api.Test;
import org.openjdk.jmh.annotations.*;
import top.csaf.CollectionUtils;
import top.csaf.tree.TreeNode;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* 生成树节点列表性能测试
*/
@State(Scope.Benchmark)
@Threads(1)
@Fork(1)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 5, time = 1)
@BenchmarkMode(Mode.All)
public class BuildTreeNodeListTest {
public static void main(String[] args) {
BuildTreeNodeListTest buildTreeNodeListTest = new BuildTreeNodeListTest();
System.out.println(CollectionUtils.isAllEqualsSameIndex(true, null,
buildTreeNodeListTest.build(),
buildTreeNodeListTest.buildByRecursive(),
buildTreeNodeListTest.buildByMap()
));
}
@Test
void benchmark() throws Exception {
org.openjdk.jmh.Main.main(new String[]{BuildTreeNodeListTest.class.getName()});
}
private static final List<TreeNode> TREE_NODE_LIST = new ArrayList<>();
static {
TREE_NODE_LIST.add(new TreeNode("1", "1", 1, "0"));
TREE_NODE_LIST.add(new TreeNode("2", "1.1", 1, "1"));
TREE_NODE_LIST.add(new TreeNode("3", "1.2", 2, "1"));
TREE_NODE_LIST.add(new TreeNode("7", "1.2.3", 3, "3"));
TREE_NODE_LIST.add(new TreeNode("6", "1.2.2", 2, "3"));
TREE_NODE_LIST.add(new TreeNode("5", "1.2.1", 1, "3"));
TREE_NODE_LIST.add(new TreeNode("4", "1.3", 3, "1"));
TREE_NODE_LIST.add(new TreeNode("8", "2", 2, "0"));
TREE_NODE_LIST.add(new TreeNode("9", "2.1", 1, "8"));
TREE_NODE_LIST.add(new TreeNode("12", "2.1.2", 2, "9"));
TREE_NODE_LIST.add(new TreeNode("13", "2.1.2.1", 1, "12"));
TREE_NODE_LIST.add(new TreeNode("15", "2.1.2.3", 3, "12"));
TREE_NODE_LIST.add(new TreeNode("14", "2.1.2.2", 2, "12"));
TREE_NODE_LIST.add(new TreeNode("11", "2.1.1", 1, "9"));
TREE_NODE_LIST.add(new TreeNode("10", "2.2", 2, "8"));
}
/**
* 双层循环
* <p>
* 来源:<a href="https://blog.csdn.net/massivestars/article/details/53911620/">将 List 转成树的两种方式(递归、循环)</a>
*
* @return 树列表
*/
@Benchmark
public List<TreeNode> build() {
List<TreeNode> trees = new LinkedList<>();
for (TreeNode treeNode : TREE_NODE_LIST) {
// 如果是顶级节点则直接添加
if ("0".equals(treeNode.getParentId())) {
trees.add(treeNode);
}
// 双层循环
for (TreeNode treeNode1 : TREE_NODE_LIST) {
// 如果二层循环节点的父级 ID = 一层循环节点的 ID
if (treeNode1.getParentId().equals(treeNode.getId())) {
// 则将其添加到一层循环节点的 children 中
if (treeNode.getChildren() == null) {
treeNode.setChildren(new LinkedList<>());
}
treeNode.getChildren().add(treeNode1);
}
}
}
return trees;
}
public static TreeNode findChildren(TreeNode treeNode, List<TreeNode> treeNodes) {
for (TreeNode it : treeNodes) {
if (treeNode.getId().equals(it.getParentId())) {
if (treeNode.getChildren() == null) {
treeNode.setChildren(new ArrayList<TreeNode>());
}
treeNode.getChildren().add(findChildren(it, treeNodes));
}
}
return treeNode;
}
/**
* 递归
* <p>
* 来源:<a href="https://blog.csdn.net/massivestars/article/details/53911620/">将 List 转成树的两种方式(递归、循环)</a>
*
* @return 树列表
*/
@Benchmark
public List<TreeNode> buildByRecursive() {
Set<TreeNode> trees = new HashSet<>();
for (TreeNode treeNode : TREE_NODE_LIST) {
if ("0".equals(treeNode.getParentId())) {
trees.add(findChildren(treeNode, TREE_NODE_LIST));
}
}
return new ArrayList<>(trees);
}
/**
* Map
* <p>
* 来源:<a href="https://blog.csdn.net/imyc7/article/details/112380154">高效的将 List 转换成 Tree</a>
*
* @return 树列表
*/
@Benchmark
public List<TreeNode> buildByMap() {
// id 为 key,value 为自身存储到 Map 中
Map<String, TreeNode> treeNodeMap = new LinkedHashMap<>(TREE_NODE_LIST.size());
for (TreeNode treeNode : TREE_NODE_LIST) {
treeNodeMap.put(treeNode.getId().toString(), treeNode);
}
List<TreeNode> treeList = new ArrayList<>();
for (TreeNode treeNode : TREE_NODE_LIST) {
// 根据当前节点的父级 ID 获取父级节点
TreeNode parent = treeNodeMap.get(treeNode.getParentId().toString());
// 如果没有父节点
if (parent == null) {
// 则为顶级节点
treeList.add(treeNode);
} else {
// 如果没有子节点列表,则创建列表
if (parent.getChildren() == null) {
parent.setChildren(new ArrayList<>());
}
// 将自身添加到父节点的子节点列表中
parent.getChildren().add(treeNode);
}
}
return treeList;
}
}
// Benchmark Mode Cnt Score Error Units
// BuildTreeNodeListTest.build thrpt 5 0.864 ± 1.543 ops/us
// BuildTreeNodeListTest.buildByMap thrpt 5 1.697 ± 4.151 ops/us
// BuildTreeNodeListTest.buildByRecursive thrpt 5 ≈ 10⁻⁵ ops/us
// BuildTreeNodeListTest.build avgt 5 2.182 ± 10.494 us/op
// BuildTreeNodeListTest.buildByMap avgt 5 1.815 ± 10.738 us/op
// BuildTreeNodeListTest.buildByRecursive avgt 5 126878.579 ± 80184.045 us/op
// BuildTreeNodeListTest.build sample 140719 41.806 ± 133.978 us/op
// BuildTreeNodeListTest.build:build·p0.00 sample 0.900 us/op
// BuildTreeNodeListTest.build:build·p0.50 sample 1.100 us/op
// BuildTreeNodeListTest.build:build·p0.90 sample 1.100 us/op
// BuildTreeNodeListTest.build:build·p0.95 sample 1.200 us/op
// BuildTreeNodeListTest.build:build·p0.99 sample 2.300 us/op
// BuildTreeNodeListTest.build:build·p0.999 sample 3.600 us/op
// BuildTreeNodeListTest.build:build·p0.9999 sample 20.288 us/op
// BuildTreeNodeListTest.build:build·p1.00 sample 5729419.264 us/op
// BuildTreeNodeListTest.buildByMap sample 127848 0.446 ± 0.003 us/op
// BuildTreeNodeListTest.buildByMap:buildByMap·p0.00 sample 0.300 us/op
// BuildTreeNodeListTest.buildByMap:buildByMap·p0.50 sample 0.400 us/op
// BuildTreeNodeListTest.buildByMap:buildByMap·p0.90 sample 0.500 us/op
// BuildTreeNodeListTest.buildByMap:buildByMap·p0.95 sample 0.500 us/op
// BuildTreeNodeListTest.buildByMap:buildByMap·p0.99 sample 1.300 us/op
// BuildTreeNodeListTest.buildByMap:buildByMap·p0.999 sample 2.900 us/op
// BuildTreeNodeListTest.buildByMap:buildByMap·p0.9999 sample 23.065 us/op
// BuildTreeNodeListTest.buildByMap:buildByMap·p1.00 sample 41.984 us/op
// BuildTreeNodeListTest.buildByRecursive sample 43 124359.894 ± 11243.885 us/op
// BuildTreeNodeListTest.buildByRecursive:buildByRecursive·p0.00 sample 92667.904 us/op
// BuildTreeNodeListTest.buildByRecursive:buildByRecursive·p0.50 sample 122814.464 us/op
// BuildTreeNodeListTest.buildByRecursive:buildByRecursive·p0.90 sample 155608.678 us/op
// BuildTreeNodeListTest.buildByRecursive:buildByRecursive·p0.95 sample 165884.723 us/op
// BuildTreeNodeListTest.buildByRecursive:buildByRecursive·p0.99 sample 167247.872 us/op
// BuildTreeNodeListTest.buildByRecursive:buildByRecursive·p0.999 sample 167247.872 us/op
// BuildTreeNodeListTest.buildByRecursive:buildByRecursive·p0.9999 sample 167247.872 us/op
// BuildTreeNodeListTest.buildByRecursive:buildByRecursive·p1.00 sample 167247.872 us/op
// BuildTreeNodeListTest.build ss 5 36.200 ± 13.494 us/op
// BuildTreeNodeListTest.buildByMap ss 5 16.460 ± 9.240 us/op
// BuildTreeNodeListTest.buildByRecursive ss 5 139.360 ± 97.022 us/op
...@@ -12,7 +12,7 @@ import java.nio.charset.Charset; ...@@ -12,7 +12,7 @@ import java.nio.charset.Charset;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@DisplayName("数组工具类测试") @DisplayName("数组工具类测试")
public class ArrayUtilsTest { class ArrayUtilsTest {
@DisplayName("toBytesAndToString:转字节数组和转字符串") @DisplayName("toBytesAndToString:转字节数组和转字符串")
@Test @Test
......
package top.csaf.junit; package top.csaf.junit;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
...@@ -21,6 +22,7 @@ public class BeanUtilsTest { ...@@ -21,6 +22,7 @@ public class BeanUtilsTest {
private String superName; private String superName;
} }
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor @NoArgsConstructor
@Data @Data
public static class TestBean extends TestSuperBean implements Serializable { public static class TestBean extends TestSuperBean implements Serializable {
......
...@@ -7,7 +7,7 @@ import top.csaf.ClassUtils; ...@@ -7,7 +7,7 @@ import top.csaf.ClassUtils;
@Slf4j @Slf4j
@DisplayName("Class 工具类测试") @DisplayName("Class 工具类测试")
public class ClassUtilsTest { class ClassUtilsTest {
private void println(Object source) { private void println(Object source) {
System.out.println(source); System.out.println(source);
......
...@@ -19,7 +19,7 @@ import static org.junit.jupiter.api.Assertions.*; ...@@ -19,7 +19,7 @@ import static org.junit.jupiter.api.Assertions.*;
@Slf4j @Slf4j
@DisplayName("集合工具类测试") @DisplayName("集合工具类测试")
public class CollectionUtilsTest { class CollectionUtilsTest {
public static void main(String[] args) { public static void main(String[] args) {
genCollections4Fn(); genCollections4Fn();
......
...@@ -17,7 +17,7 @@ import java.util.Locale; ...@@ -17,7 +17,7 @@ import java.util.Locale;
@Slf4j @Slf4j
@DisplayName("时间工具类测试") @DisplayName("时间工具类测试")
public class DateUtilsTest { class DateUtilsTest {
private final ZonedDateTime nowZonedDateTime = ZonedDateTime.now(); private final ZonedDateTime nowZonedDateTime = ZonedDateTime.now();
private final LocalDateTime nowLocalDateTime = LocalDateTime.now(); private final LocalDateTime nowLocalDateTime = LocalDateTime.now();
......
...@@ -10,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; ...@@ -10,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
@Slf4j @Slf4j
@DisplayName("文件工具类测试") @DisplayName("文件工具类测试")
public class FileUtilsTest { class FileUtilsTest {
private static final String PROJECT_PATH = FileUtils.getUserDir(); private static final String PROJECT_PATH = FileUtils.getUserDir();
private static final String PROJECT_PATH_SLASH = FileUtils.getUserDir().replace("\\", "/"); private static final String PROJECT_PATH_SLASH = FileUtils.getUserDir().replace("\\", "/");
......
...@@ -21,7 +21,7 @@ import java.util.Map; ...@@ -21,7 +21,7 @@ import java.util.Map;
@Slf4j @Slf4j
@DisplayName("HTTP 工具类测试") @DisplayName("HTTP 工具类测试")
public class HttpUtilsTest { class HttpUtilsTest {
@DisplayName("获取 Media Types") @DisplayName("获取 Media Types")
@Test @Test
......
...@@ -24,7 +24,7 @@ import java.util.regex.Pattern; ...@@ -24,7 +24,7 @@ import java.util.regex.Pattern;
@Slf4j @Slf4j
@DisplayName("拼音工具类测试") @DisplayName("拼音工具类测试")
public class PinyinUtilsTest { class PinyinUtilsTest {
private static final Pattern PINYIN_PATTERN_A = Pattern.compile("[āáǎà]"); private static final Pattern PINYIN_PATTERN_A = Pattern.compile("[āáǎà]");
private static final Pattern PINYIN_PATTERN_O = Pattern.compile("[ōóǒò]"); private static final Pattern PINYIN_PATTERN_O = Pattern.compile("[ōóǒò]");
......
...@@ -13,7 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; ...@@ -13,7 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
@Slf4j @Slf4j
@DisplayName("正则工具类测试") @DisplayName("正则工具类测试")
public class RegExUtilsTest { class RegExUtilsTest {
@Test @Test
void testCodeCoverage() { void testCodeCoverage() {
......
...@@ -13,7 +13,7 @@ import java.security.spec.InvalidKeySpecException; ...@@ -13,7 +13,7 @@ import java.security.spec.InvalidKeySpecException;
@Slf4j @Slf4j
@DisplayName("加密解密工具类测试") @DisplayName("加密解密工具类测试")
public class SecurityUtilsTest { class SecurityUtilsTest {
private void println(Object source) { private void println(Object source) {
System.out.println(source); System.out.println(source);
......
...@@ -9,7 +9,7 @@ import java.util.Collections; ...@@ -9,7 +9,7 @@ import java.util.Collections;
@Slf4j @Slf4j
@DisplayName("字符串工具类测试") @DisplayName("字符串工具类测试")
public class StringUtilsTest { class StringUtilsTest {
private void println(Object source) { private void println(Object source) {
System.out.println(source); System.out.println(source);
......
package top.csaf.junit;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import top.csaf.tree.TreeConfig;
import top.csaf.tree.TreeNode;
import top.csaf.tree.TreeUtils;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@Slf4j
@DisplayName("树工具类测试")
class TreeUtilsTest {
private final List<TreeNode> TREE_NODE_LIST = new ArrayList<>();
{
TREE_NODE_LIST.add(new TreeNode(1, "1", 1, "0"));
TREE_NODE_LIST.add(new TreeNode(2, "1.1", 1, "1"));
TREE_NODE_LIST.add(new TreeNode(3, "1.2", 2, "1"));
TREE_NODE_LIST.add(new TreeNode(7, "1.2.3", 3, "3"));
TREE_NODE_LIST.add(new TreeNode(6, "1.2.2", 2, "3"));
TREE_NODE_LIST.add(new TreeNode(5, "1.2.1", 1, "3"));
TREE_NODE_LIST.add(new TreeNode(4, "1.3", 3, "1"));
TREE_NODE_LIST.add(new TreeNode(8, "2", 2, "0"));
TREE_NODE_LIST.add(new TreeNode(9, "2.1", 1, "8"));
TREE_NODE_LIST.add(new TreeNode(12, "2.1.2", 2, "9"));
TREE_NODE_LIST.add(new TreeNode(13, "2.1.2.1", 1, "12"));
TREE_NODE_LIST.add(new TreeNode(15, "2.1.2.3", 3, "12"));
TREE_NODE_LIST.add(new TreeNode(14, "2.1.2.2", 2, "12"));
TREE_NODE_LIST.add(new TreeNode(11, "2.1.1", 1, "9"));
TREE_NODE_LIST.add(new TreeNode(10, "2.2", 2, "8"));
TREE_NODE_LIST.add(new TreeNode(999, "9", 999, "000"));
}
@DisplayName("构建树")
@Test
void build() {
/** {@link TreeUtils#bulid(List)} */
List<TreeNode> treeNodeList = TreeUtils.build(TREE_NODE_LIST);
// 默认不排序所以 1.2.3 在第一个
assertEquals("1.2.3", treeNodeList.get(0).getChildren().get(1).getChildren().get(0).getName());
/** {@link TreeUtils#bulid(List, TreeConfig)} */
TreeConfig treeConfig = new TreeConfig();
treeConfig.setSort(true);
treeConfig.setComparator(null);
assertThrows(IllegalArgumentException.class, () -> TreeUtils.build(TREE_NODE_LIST, treeConfig));
// 排序后
treeConfig.setComparator(Comparator.nullsFirst(Comparator.comparing(TreeNode::getId, Comparator.comparingInt(s -> Integer.parseInt(s.toString())))));
assertEquals("1.2.1", TreeUtils.build(TREE_NODE_LIST, treeConfig).get(0).getChildren().get(1).getChildren().get(0).getName());
// 排序前
treeConfig.setSort(false);
assertEquals("1.2.3", TreeUtils.build(TREE_NODE_LIST, treeConfig).get(0).getChildren().get(1).getChildren().get(0).getName());
// 找不到父类也为顶级节点
treeConfig.setRootByNullParent(true);
assertEquals(999, TreeUtils.build(TREE_NODE_LIST, treeConfig).get(2).getId());
}
}
...@@ -13,7 +13,7 @@ import top.csaf.io.FileUtils; ...@@ -13,7 +13,7 @@ import top.csaf.io.FileUtils;
@Slf4j @Slf4j
@DisplayName("XML 工具类测试") @DisplayName("XML 工具类测试")
public class XmlUtilsTest { class XmlUtilsTest {
private void println(Object source) { private void println(Object source) {
System.out.println(source); System.out.println(source);
......
...@@ -10,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; ...@@ -10,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
@Slf4j @Slf4j
@DisplayName("YAML 工具类测试") @DisplayName("YAML 工具类测试")
public class YamlUtilsTest { class YamlUtilsTest {
private static final String YML_FILE_PATH = FileUtils.getProjectPath() + "/src/test/java/top/csaf/assets/yaml/test.yml"; private static final String YML_FILE_PATH = FileUtils.getProjectPath() + "/src/test/java/top/csaf/assets/yaml/test.yml";
......
...@@ -5,7 +5,7 @@ import org.junit.jupiter.api.Test; ...@@ -5,7 +5,7 @@ import org.junit.jupiter.api.Test;
import top.csaf.id.SnowFlake; import top.csaf.id.SnowFlake;
@DisplayName("雪花算法测试") @DisplayName("雪花算法测试")
public class SnowFlakeTest { class SnowFlakeTest {
@DisplayName("简单实现") @DisplayName("简单实现")
@Test @Test
......