diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/func/ComposeFunction.java b/hutool-core/src/main/java/cn/hutool/core/lang/func/ComposeFunction.java new file mode 100644 index 000000000..80d4b3178 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/func/ComposeFunction.java @@ -0,0 +1,46 @@ +package cn.hutool.core.lang.func; + +import cn.hutool.core.lang.Assert; + +import java.io.Serializable; +import java.util.function.Function; + +/** + * 两个函数的叠加函数. 叠加 {@code f: A->B} 和 {@code g: B->C},效果等同于:{@code h(a) == g(f(a))} + * + * @param 第一个函数的传入参数类型 + * @param 第一个函数的返回类型(第二个函数有的参数类型) + * @param 最终结果类型 + * @author Guava + * @since 6.0.0 + */ +public class ComposeFunction implements Function, Serializable { + private static final long serialVersionUID = 1L; + + /** + * 两个函数的叠加函数. 叠加 {@code f: A->B} 和 {@code g: B->C},效果等同于:{@code h(a) == g(f(a))} + * + * @param g 第二个函数 + * @param f 第一个函数 + * @param 第一个函数的传入参数类型 + * @param 第一个函数的返回类型(第二个函数有的参数类型) + * @param 最终结果类型 + * @return 叠加函数 + */ + public static ComposeFunction of(final Function g, final Function f) { + return new ComposeFunction<>(g, f); + } + + private final Function g; + private final Function f; + + public ComposeFunction(final Function g, final Function f) { + this.g = Assert.notNull(g); + this.f = Assert.notNull(f); + } + + @Override + public C apply(final A a) { + return g.apply(f.apply(a)); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java index d69fd6e60..ea4d282f7 100755 --- a/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/func/LambdaUtil.java @@ -132,6 +132,8 @@ public class LambdaUtil { return BeanUtil.getFieldName(getMethodName(func)); } + + //region Private methods /** diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/func/PredicateUtil.java b/hutool-core/src/main/java/cn/hutool/core/lang/func/PredicateUtil.java new file mode 100644 index 000000000..4efc35232 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/func/PredicateUtil.java @@ -0,0 +1,138 @@ +package cn.hutool.core.lang.func; + +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.text.StrUtil; + +import java.io.Serializable; +import java.util.List; +import java.util.function.Predicate; + +/** + * 一些{@link Predicate}相关封装 + * + * @author looly + * @since 6.0.0 + */ +public class PredicateUtil { + + public static Predicate negate(final Predicate predicate) { + return predicate.negate(); + } + + /** + * 多个条件转换为”与“复合条件,即所有条件都为true时,才返回true + * + * @param 判断条件的对象类型 + * @param components 多个条件 + * @return 复合条件 + */ + public static Predicate and(final Iterable> components) { + return new AndPredicate<>(ListUtil.of(components)); + } + + /** + * 多个条件转换为”与“复合条件,即所有条件都为true时,才返回true + * + * @param 判断条件的对象类型 + * @param components 多个条件 + * @return 复合条件 + */ + @SuppressWarnings("unchecked") + public static Predicate and(final Predicate... components) { + return new AndPredicate<>(components); + } + + /** + * 多个条件转换为”或“复合条件,即任意一个条件都为true时,返回true + * + * @param 判断条件的对象类型 + * @param components 多个条件 + * @return 复合条件 + */ + public static Predicate or(final Iterable> components) { + return new OrPredicate<>(ListUtil.of(components)); + } + + /** + * 多个条件转换为”或“复合条件,即任意一个条件都为true时,返回true + * + * @param 判断条件的对象类型 + * @param components 多个条件 + * @return 复合条件 + */ + @SuppressWarnings("unchecked") + public static Predicate or(final Predicate... components) { + return new OrPredicate<>(components); + } + + /** + * 多个{@link Predicate}的与,只有所有条件满足才为true,当任意一个条件的test为false,返回false + * + * @param 泛型类型 + * @author Guava + */ + private static class AndPredicate implements Predicate, Serializable { + private static final long serialVersionUID = 1L; + + private final List> components; + + @SafeVarargs + private AndPredicate(final Predicate... components) { + this.components = ListUtil.of(components); + } + + private AndPredicate(final List> components) { + this.components = components; + } + + @Override + public boolean test(final T t) { + // Avoid using the Iterator to avoid generating garbage + //noinspection ForLoopReplaceableByForEach + for (int i = 0; i < components.size(); i++) { + if (false == components.get(i).test(t)) { + return false; + } + } + return true; + } + + @Override + public String toString() { + return "Predicates.and(" + StrUtil.join(",", this.components) + ")"; + } + } + + /** + * 多个{@link Predicate}的或操作,即当一个条件满足,则全部满足,当任意一个条件的test为true,返回true + * + * @param 泛型类型 + * @author Guava + */ + private static class OrPredicate implements Predicate, Serializable { + private static final long serialVersionUID = 1L; + + private final List> components; + + @SafeVarargs + private OrPredicate(final Predicate... components) { + this.components = ListUtil.of(components); + } + + private OrPredicate(final List> components) { + this.components = components; + } + + @Override + public boolean test(final T t) { + // Avoid using the Iterator to avoid generating garbage + //noinspection ForLoopReplaceableByForEach + for (int i = 0; i < components.size(); i++) { + if (false == components.get(i).test(t)) { + return true; + } + } + return false; + } + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaUtilTest.java index 16660af6f..e923a604a 100644 --- a/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/lang/func/LambdaUtilTest.java @@ -16,14 +16,14 @@ public class LambdaUtilTest { @Test public void getMethodNameTest() { - Func1 lambda = MyTeacher::getAge; + final Func1 lambda = MyTeacher::getAge; final String methodName = LambdaUtil.getMethodName(lambda); Assert.assertEquals("getAge", methodName); } @Test public void getFieldNameTest() { - Func1 lambda = MyTeacher::getAge; + final Func1 lambda = MyTeacher::getAge; final String fieldName = LambdaUtil.getFieldName(lambda); Assert.assertEquals("age", fieldName); } @@ -32,43 +32,45 @@ public class LambdaUtilTest { public void resolveTest() { Stream.of(() -> { // 引用构造函数 - Func0 lambda = MyTeacher::new; - LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); + final Func0 lambda = MyTeacher::new; + final LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); Assert.assertEquals(0, lambdaInfo.getParameterTypes().length); Assert.assertEquals(MyTeacher.class, lambdaInfo.getReturnType()); }, () -> { // 数组构造函数引用(此处数组构造参数) - Func1 lambda = MyTeacher[]::new; - LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); + final Func1 lambda = MyTeacher[]::new; + final LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); Assert.assertEquals(int.class, lambdaInfo.getParameterTypes()[0]); Assert.assertEquals(MyTeacher.class, ((Class) lambdaInfo.getReturnType()).getComponentType()); }, () -> { // 引用静态方法 - Func0 lambda = MyTeacher::takeAge; - LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); + final Func0 lambda = MyTeacher::takeAge; + final LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); Assert.assertEquals(0, lambdaInfo.getParameterTypes().length); Assert.assertEquals(String.class, lambdaInfo.getReturnType()); }, () -> { // 引用特定对象的实例方法 - Func0 lambda = new MyTeacher()::getAge; - LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); + final Func0 lambda = new MyTeacher()::getAge; + final LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); Assert.assertEquals(0, lambdaInfo.getParameterTypes().length); Assert.assertEquals(String.class, lambdaInfo.getReturnType()); }, () -> { // 引用特定类型的任意对象的实例方法 - Func1 lambda = MyTeacher::getAge; - LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); + final Func1 lambda = MyTeacher::getAge; + final LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); Assert.assertEquals(0, lambdaInfo.getParameterTypes().length); Assert.assertEquals(String.class, lambdaInfo.getReturnType()); }, () -> { // 最最重要的!!! - Character character = '0'; - Integer integer = 0; - SerThiCons lambda = (obj, bool, str) -> { + final Character character = '0'; + final Integer integer = 0; + final SerThiCons lambda = (obj, bool, str) -> { + //noinspection ResultOfMethodCallIgnored Objects.nonNull(character); + //noinspection ResultOfMethodCallIgnored Objects.nonNull(integer); }; - LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); + final LambdaInfo lambdaInfo = LambdaUtil.resolve(lambda); // 获取闭包使用的参数类型 Assert.assertEquals(Character.class, lambdaInfo.getParameterTypes()[0]); Assert.assertEquals(Integer.class, lambdaInfo.getParameterTypes()[1]); @@ -102,35 +104,36 @@ public class LambdaUtilTest { Assert.assertEquals(MyTeacher.class, LambdaUtil.getRealClass(lambda)); }, () -> { // 引用特定对象的实例方法 - Func0 lambda = myTeacher::getAge; + final Func0 lambda = myTeacher::getAge; Assert.assertEquals(MyTeacher.class, LambdaUtil.getRealClass(lambda)); }, () -> { // 枚举测试,只能获取到枚举类型 - Func0 lambda = LambdaKindEnum.REF_NONE::ordinal; + final Func0 lambda = LambdaKindEnum.REF_NONE::ordinal; Assert.assertEquals(Enum.class, LambdaUtil.getRealClass(lambda)); }, () -> { // 调用父类方法,只能获取到父类类型 - VoidFunc0 lambda = myTeacher::getId; + //noinspection ResultOfMethodCallIgnored + final VoidFunc0 lambda = myTeacher::getId; Assert.assertEquals(Entity.class, LambdaUtil.getRealClass(lambda)); }, () -> { // 引用静态带参方法,能够获取到正确的参数类型 - Func1 lambda = MyTeacher::takeAgeBy; + final Func1 lambda = MyTeacher::takeAgeBy; Assert.assertEquals(MyTeacher.class, LambdaUtil.getRealClass(lambda)); }, () -> { // 引用父类静态带参方法,只能获取到父类类型 - Func0 lambda = MyTeacher::takeId; + final Func0 lambda = MyTeacher::takeId; Assert.assertEquals(Entity.class, LambdaUtil.getRealClass(lambda)); }, () -> { // 引用静态无参方法,能够获取到正确的类型 - Func0 lambda = MyTeacher::takeAge; + final Func0 lambda = MyTeacher::takeAge; Assert.assertEquals(MyTeacher.class, LambdaUtil.getRealClass(lambda)); }, () -> { // 引用父类静态无参方法,能够获取到正确的参数类型 - Func1 lambda = MyTeacher::takeIdBy; + final Func1 lambda = MyTeacher::takeIdBy; Assert.assertEquals(MyTeacher.class, LambdaUtil.getRealClass(lambda)); }, () -> { // 数组测试 - VoidFunc1 lambda = (String[] stringList) -> {}; + final VoidFunc1 lambda = (String[] stringList) -> {}; Assert.assertEquals(String[].class, LambdaUtil.getRealClass(lambda)); }).forEach(Runnable::run); } @@ -176,6 +179,7 @@ public class LambdaUtilTest { /** * 测试Lambda类型枚举 */ + @SuppressWarnings("unused") enum LambdaKindEnum { REF_NONE, REF_getField, diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/func/PredicateUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/func/PredicateUtilTest.java new file mode 100644 index 000000000..83d2029a8 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/lang/func/PredicateUtilTest.java @@ -0,0 +1,25 @@ +package cn.hutool.core.lang.func; + +import cn.hutool.core.collection.SetUtil; +import org.junit.Assert; +import org.junit.Test; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class PredicateUtilTest { + + @Test + public void notContainsTest(){ + final Set sets = SetUtil.of("1", "2", "3"); + final List collect = Stream.of("3", "4", "5") + .filter(PredicateUtil.negate(sets::contains)) + .collect(Collectors.toList()); + + Assert.assertEquals(2, collect.size()); + Assert.assertEquals("4", collect.get(0)); + Assert.assertEquals("5", collect.get(1)); + } +}