This commit is contained in:
Looly 2023-05-03 22:15:11 +08:00
parent 6b68efb627
commit b92c91a134
8 changed files with 349 additions and 242 deletions

View File

@ -1,221 +0,0 @@
package org.dromara.hutool.core.lang.hierarchy;
import org.dromara.hutool.core.lang.mutable.Mutable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* 用于遍历层级结构的迭代器提供了遍历过程中的回调方法
* <ul>
* <li>{@link #isBreak}: 是否中断遍历其在{@link #nextHierarchies}之前调用</li>
* <li>{@link #nextHierarchies}: 获得下一需要遍历的层级当为空时结束</li>
* <li>{@link #getResult}: 当遍历完成后获取迭代器结果</li>
* </ul>
*
* <p>默认提供了三类{@link HierarchyIterator}实现
* <ul>
* <li>scan: 遍历所有的层级结构</li>
* <li>collector: 收集层级结构中所有符合条件的结果并在结束遍历后返回所有结果</li>
* <li>find: 找到层级结构中符合条件的结果后立刻中断遍历并返回该结果</li>
* </ul>
* 可以实现自定义的{@link HierarchyIterator}来支持更多的遍历模式
*
* @param <H> 层级类型
* @param <R> 结果类型
* @author huangchengxing
* @since 6.0.0
*/
@FunctionalInterface
public interface HierarchyIterator<H, R> {
/**
* 获取下一层级
*
* @param result 结果
* @param hierarchy 当前层级
* @return 向容器中添加元素的方法
*/
Collection<H> nextHierarchies(R result, H hierarchy);
/**
* 是否中断遍历
*
* @param hierarchy 当前层级
* @return 是否中断遍历
*/
default boolean isBreak(H hierarchy) {
return false;
}
/**
* 获取结果
*
* @return 结果
*/
default R getResult() {
return null;
}
/**
* 创建一个{@link HierarchyIterator}对象, {@code finder}返回非空时, 迭代器立刻中断, 返回结果
*
* @param function 迭代器处理函数
* @param finder 查找器
* @param <H> 层级结构类型
* @param <R> 迭代器结果类型
* @return {@link HierarchyIterator}
*/
static <H, R> HierarchyIterator<H, R> find(
final Function<H, Collection<H>> function, final Function<H, R> finder) {
Objects.requireNonNull(function);
Objects.requireNonNull(finder);
final Mutable<R> mutable = Mutable.of(null);
final Predicate<H> terminator = h -> {
R r = finder.apply(h);
if (r != null) {
mutable.set(r);
return true;
}
return false;
};
return new HierarchyIteratorImpl<>(mutable::get, terminator, (r, h) -> function.apply(h));
}
/**
* 创建一个{@link HierarchyIterator}对象, 迭代器结果总是为{@code null}
*
* @param function 迭代器处理函数
* @param terminator 是否终止遍历
* @param <H> 层级结构类型
* @return {@link HierarchyIterator}
*/
static <H> HierarchyIterator<H, Void> scan(
final Function<H, Collection<H>> function, final Predicate<H> terminator) {
Objects.requireNonNull(function);
return new HierarchyIteratorImpl<>(() -> null, terminator, (r, h) -> function.apply(h));
}
/**
* 创建一个{@link HierarchyIterator}对象, 迭代器结果总是为{@code null}
*
* @param function 迭代器处理函数
* @param <H> 层级结构类型
* @return {@link HierarchyIterator}
*/
static <H> HierarchyIterator<H, Void> scan(final Function<H, Collection<H>> function) {
return scan(function, h -> false);
}
/**
* 创建一个{@link HierarchyIterator}对象, {@code mapper}返回非空, 则将结果添加到集合中最终返回集合
*
* @param function 迭代器处理函数
* @param collFactory 集合工厂
* @param mapper 迭代器结果映射函数
* @param <H> 层级结构类型
* @param <R> 迭代器结果类型
* @param <C> 集合类型
* @return {@link HierarchyIterator}
*/
static <H, R, C extends Collection<R>> HierarchyIterator<H, C> collect(
final Function<H, Collection<H>> function, final Supplier<C> collFactory, final Function<H, R> mapper) {
Objects.requireNonNull(function);
Objects.requireNonNull(collFactory);
Objects.requireNonNull(mapper);
final C collection = collFactory.get();
return new HierarchyIteratorImpl<>(() -> collection, h -> false, (r, h) -> {
final R apply = mapper.apply(h);
if (Objects.nonNull(apply)) {
collection.add(apply);
}
return function.apply(h);
});
}
/**
* 创建一个{@link HierarchyIterator}对象, {@code mapper}返回非空, 则将结果添加到集合中最终返回集合
*
* @param function 迭代器处理函数
* @param mapper 迭代器结果映射函数
* @param <H> 层级结构类型
* @param <R> 迭代器结果类型
* @return {@link HierarchyIterator}
*/
static <H, R> HierarchyIterator<H, List<R>> collect(
final Function<H, Collection<H>> function, final Function<H, R> mapper) {
return collect(function, ArrayList::new, mapper);
}
/**
* 创建一个{@link HierarchyIterator}对象, 则将非空结果添加到集合中最终返回集合
*
* @param function 迭代器处理函数
* @param <H> 层级结构类型
* @return {@link HierarchyIterator}
*/
static <H> HierarchyIterator<H, List<H>> collect(
final Function<H, Collection<H>> function) {
return collect(function, Function.identity());
}
/**
* {@link HierarchyIterator}的基本实现
*
* @param <H> 层级类型
* @param <R> 结果类型
*/
class HierarchyIteratorImpl<H, R> implements HierarchyIterator<H, R> {
private final Supplier<? extends R> resultFactory;
private final Predicate<? super H> hierarchyFilter;
private final BiFunction<? super R, ? super H, ? extends Collection<H>> hierarchyFinder;
public HierarchyIteratorImpl(
final Supplier<? extends R> resultFactory, final Predicate<? super H> hierarchyFilter,
final BiFunction<? super R, ? super H, ? extends Collection<H>> hierarchyFinder) {
this.resultFactory = resultFactory;
this.hierarchyFilter = hierarchyFilter;
this.hierarchyFinder = hierarchyFinder;
}
/**
* 获取下一层级
*
* @param result 结果
* @param hierarchy 当前层级
* @return 向容器中添加元素的方法
*/
@Override
public Collection<H> nextHierarchies(final R result, final H hierarchy) {
return hierarchyFinder.apply(result, hierarchy);
}
/**
* 是否中断遍历
*
* @param hierarchy 当前层级
* @return 是否中断遍历
*/
@Override
public boolean isBreak(final H hierarchy) {
return hierarchyFilter.test(hierarchy);
}
/**
* 获取结果
*
* @return 结果
*/
@Override
public R getResult() {
return resultFactory.get();
}
}
}

View File

@ -13,6 +13,7 @@
package org.dromara.hutool.core.text;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.func.FunctionPool;
import org.dromara.hutool.core.text.placeholder.StrFormatter;
import org.dromara.hutool.core.util.CharsetUtil;
@ -219,6 +220,17 @@ public class StrUtil extends CharSequenceUtil implements StrPool {
}
return charset.decode(data).toString();
}
/**
* JDK8中通过{@code String(char[] value, boolean share)}这个内部构造创建String对象<br>
* 此函数通过传入char[]实现zero-copy的String创建效率很高但是要求传入的char[]不可以在其他地方修改
*
* @param value char[]注意这个数组不可修改
* @return String
*/
public static String strFast(final char[] value){
return FunctionPool.createString(value);
}
// endregion
/**

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.tree.hierarchy;
import java.util.Collection;
/**
* 用于遍历层级结构的迭代器提供了遍历过程中的回调方法
* <ul>
* <li>{@link #isBreak}: 是否中断遍历其在{@link #nextHierarchies}之前调用</li>
* <li>{@link #nextHierarchies}: 获得下一需要遍历的层级当为空时结束</li>
* <li>{@link #getResult}: 当遍历完成后获取迭代器结果</li>
* </ul>
*
* <p>默认提供了三类{@code HierarchyIterator}实现
* <ul>
* <li>scan: 遍历所有的层级结构</li>
* <li>collector: 收集层级结构中所有符合条件的结果并在结束遍历后返回所有结果</li>
* <li>find: 找到层级结构中符合条件的结果后立刻中断遍历并返回该结果</li>
* </ul>
* 可以实现自定义的{@code HierarchyIterator}来支持更多的遍历模式
*
* @param <H> 层级类型
* @param <R> 结果类型
* @author huangchengxing
* @since 6.0.0
*/
@FunctionalInterface
public interface HierarchyIterator<H, R> {
/**
* 获取下一层级
*
* @param result 结果
* @param hierarchy 当前层级
* @return 向容器中添加元素的方法
*/
Collection<H> nextHierarchies(R result, H hierarchy);
/**
* 是否中断遍历
*
* @param hierarchy 当前层级
* @return 是否中断遍历
*/
default boolean isBreak(final H hierarchy) {
return false;
}
/**
* 获取结果
*
* @return 结果
*/
default R getResult() {
return null;
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.tree.hierarchy;
import java.util.Collection;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* {@code HierarchyIterator}的基本实现
*
* @param <H> 层级类型
* @param <R> 结果类型
* @author huangchengxing
*/
public class HierarchyIteratorImpl<H, R> implements HierarchyIterator<H, R> {
private final Supplier<? extends R> resultFactory;
private final Predicate<? super H> hierarchyFilter;
private final BiFunction<? super R, ? super H, ? extends Collection<H>> hierarchyFinder;
/**
* 构造
*
* @param resultFactory 结果创建类
* @param hierarchyFilter 层级过滤器
* @param hierarchyFinder 层级查找器
*/
public HierarchyIteratorImpl(
final Supplier<? extends R> resultFactory, final Predicate<? super H> hierarchyFilter,
final BiFunction<? super R, ? super H, ? extends Collection<H>> hierarchyFinder) {
this.resultFactory = resultFactory;
this.hierarchyFilter = hierarchyFilter;
this.hierarchyFinder = hierarchyFinder;
}
/**
* 获取下一层级
*
* @param result 结果
* @param hierarchy 当前层级
* @return 向容器中添加元素的方法
*/
@Override
public Collection<H> nextHierarchies(final R result, final H hierarchy) {
return hierarchyFinder.apply(result, hierarchy);
}
/**
* 是否中断遍历
*
* @param hierarchy 当前层级
* @return 是否中断遍历
*/
@Override
public boolean isBreak(final H hierarchy) {
return hierarchyFilter.test(hierarchy);
}
/**
* 获取结果
*
* @return 结果
*/
@Override
public R getResult() {
return resultFactory.get();
}
}

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.tree.hierarchy;
import org.dromara.hutool.core.lang.mutable.Mutable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* {@link HierarchyIterator}创建工具类
*
* @author huangchengxing
* @since 6.0.0
*/
public class HierarchyIteratorUtil {
/**
* 创建一个{@code HierarchyIterator}对象, {@code finder}返回非空时, 迭代器立刻中断, 返回结果
*
* @param function 迭代器处理函数
* @param finder 查找器
* @param <H> 层级结构类型
* @param <R> 迭代器结果类型
* @return {@code HierarchyIterator}
*/
public static <H, R> HierarchyIterator<H, R> find(
final Function<H, Collection<H>> function, final Function<H, R> finder) {
Objects.requireNonNull(function);
Objects.requireNonNull(finder);
final Mutable<R> mutable = Mutable.of(null);
final Predicate<H> terminator = h -> {
final R r = finder.apply(h);
if (r != null) {
mutable.set(r);
return true;
}
return false;
};
return new HierarchyIteratorImpl<>(mutable::get, terminator, (r, h) -> function.apply(h));
}
/**
* 创建一个{@code HierarchyIterator}对象, 迭代器结果总是为{@code null}
*
* @param function 迭代器处理函数
* @param terminator 是否终止遍历
* @param <H> 层级结构类型
* @return {@code HierarchyIterator}
*/
public static <H> HierarchyIterator<H, Void> scan(
final Function<H, Collection<H>> function, final Predicate<H> terminator) {
Objects.requireNonNull(function);
return new HierarchyIteratorImpl<>(() -> null, terminator, (r, h) -> function.apply(h));
}
/**
* 创建一个{@code HierarchyIterator}对象, 迭代器结果总是为{@code null}
*
* @param function 迭代器处理函数
* @param <H> 层级结构类型
* @return {@code HierarchyIterator}
*/
public static <H> HierarchyIterator<H, Void> scan(final Function<H, Collection<H>> function) {
return scan(function, h -> false);
}
/**
* 创建一个{@code HierarchyIterator}对象, {@code mapper}返回非空, 则将结果添加到集合中最终返回集合
*
* @param function 迭代器处理函数
* @param collFactory 集合工厂
* @param mapper 迭代器结果映射函数
* @param <H> 层级结构类型
* @param <R> 迭代器结果类型
* @param <C> 集合类型
* @return {@code HierarchyIterator}
*/
public static <H, R, C extends Collection<R>> HierarchyIterator<H, C> collect(
final Function<H, Collection<H>> function, final Supplier<C> collFactory, final Function<H, R> mapper) {
Objects.requireNonNull(function);
Objects.requireNonNull(collFactory);
Objects.requireNonNull(mapper);
final C collection = collFactory.get();
return new HierarchyIteratorImpl<>(() -> collection, h -> false, (r, h) -> {
final R apply = mapper.apply(h);
if (Objects.nonNull(apply)) {
collection.add(apply);
}
return function.apply(h);
});
}
/**
* 创建一个{@code HierarchyIterator}对象, {@code mapper}返回非空, 则将结果添加到集合中最终返回集合
*
* @param function 迭代器处理函数
* @param mapper 迭代器结果映射函数
* @param <H> 层级结构类型
* @param <R> 迭代器结果类型
* @return {@code HierarchyIterator}
*/
public static <H, R> HierarchyIterator<H, List<R>> collect(
final Function<H, Collection<H>> function, final Function<H, R> mapper) {
return collect(function, ArrayList::new, mapper);
}
/**
* 创建一个{@code HierarchyIterator}对象, 则将非空结果添加到集合中最终返回集合
*
* @param function 迭代器处理函数
* @param <H> 层级结构类型
* @return {@code HierarchyIterator}
*/
public static <H> HierarchyIterator<H, List<H>> collect(
final Function<H, Collection<H>> function) {
return collect(function, Function.identity());
}
}

View File

@ -1,4 +1,16 @@
package org.dromara.hutool.core.lang.hierarchy;
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.tree.hierarchy;
import org.dromara.hutool.core.collection.CollUtil;

View File

@ -0,0 +1,19 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* 用于处理层级结构的通用工具列结构类似 Stream + Collector<br>
* HierarchyUtil 提供深度优先和广度优先算法实现HierarchyIterator 则提供具体的操作逻辑
*
* @author huangchengxing
*/
package org.dromara.hutool.core.tree.hierarchy;

View File

@ -1,18 +1,22 @@
package org.dromara.hutool.core.lang.hierarchy;
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.core.tree.hierarchy;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -54,8 +58,8 @@ class HierarchyUtilTest {
@Test
void testTraverseByBreadthFirst() {
// 按广度优先遍历所有节点
Set<String> nodes = new LinkedHashSet<>();
HierarchyUtil.traverseByBreadthFirst("0", HierarchyIterator.scan(t -> {
final Set<String> nodes = new LinkedHashSet<>();
HierarchyUtil.traverseByBreadthFirst("0", HierarchyIteratorUtil.scan(t -> {
nodes.add(t);
return tree.entrySet().stream()
.filter(e -> Objects.equals(t, e.getValue()))
@ -69,14 +73,14 @@ class HierarchyUtilTest {
);
// 按广度优先寻找 0-2-3
String target = HierarchyUtil.traverseByBreadthFirst("0", HierarchyIterator.find(parentFinder(),
final String target = HierarchyUtil.traverseByBreadthFirst("0", HierarchyIteratorUtil.find(parentFinder(),
t -> Objects.equals(t, "0-2-3") ? t : null
));
Assertions.assertEquals("0-2-3", target);
// 按广度优先获取 0-2 的所有子节点
List<String> children = HierarchyUtil.traverseByBreadthFirst(
"0", HierarchyIterator.collect(parentFinder(),
final List<String> children = HierarchyUtil.traverseByBreadthFirst(
"0", HierarchyIteratorUtil.collect(parentFinder(),
t -> Objects.equals(tree.get(t), "0-2") ? t : null
)
);
@ -87,8 +91,8 @@ class HierarchyUtilTest {
@Test
void testTraverseByDepthFirst() {
// 按深度优先遍历所有节点
Set<String> nodes = new LinkedHashSet<>();
HierarchyUtil.traverseByDepthFirst("0", HierarchyIterator.scan(t -> {
final Set<String> nodes = new LinkedHashSet<>();
HierarchyUtil.traverseByDepthFirst("0", HierarchyIteratorUtil.scan(t -> {
nodes.add(t);
return tree.entrySet().stream()
.filter(e -> Objects.equals(t, e.getValue()))
@ -102,14 +106,14 @@ class HierarchyUtilTest {
);
// 按深度优先寻找 0-2-3
String target = HierarchyUtil.traverseByDepthFirst("0", HierarchyIterator.find(parentFinder(),
final String target = HierarchyUtil.traverseByDepthFirst("0", HierarchyIteratorUtil.find(parentFinder(),
t -> Objects.equals(t, "0-2-3") ? t : null
));
Assertions.assertEquals("0-2-3", target);
// 按深度优先获取 0-2 的所有子节点
List<String> children = HierarchyUtil.traverseByDepthFirst(
"0", HierarchyIterator.collect(parentFinder(),
final List<String> children = HierarchyUtil.traverseByDepthFirst(
"0", HierarchyIteratorUtil.collect(parentFinder(),
t -> Objects.equals(tree.get(t), "0-2") ? t : null
)
);