Java封装一个根据指定的字段来获取子集的工具类

工具类

ZhLambdaUtils

@SuppressWarnings("all")
public class ZhLambdaUtils {

    /**
     * METHOD_NAME
     */
    private static final String METHOD_NAME = "writeReplace";

    /**
     * 获取到lambda参数的方法名称
     *
     * @param <T>      parameter
     * @param function function
     * @return the name
     * @since 2023.1.1
     */
    public static <T> String getLambdaMethodName(FilterUtils.ZhFunction<T, ?> function) {
        try {
            return ((SerializedLambda) MethodUtils.invokeMethod(function, true, METHOD_NAME)).getImplMethodName();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Method to property
     *
     * @param name name
     * @return the string
     * @since 2023.1.1
     */
    public static String methodToProperty(String name) {
        if (name.startsWith("is")) {
            name = name.substring(2);
        } else {
            if (!name.startsWith("get") && !name.startsWith("set")) {
                throw new IllegalArgumentException("Error parsing property name '" + name + "'.  Didn't start with 'is', 'get' or 'set'.");
            }
            name = name.substring(3);
        }
        if (name.length() == 1 || name.length() > 1 && !Character.isUpperCase(name.charAt(1))) {
            name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
        }
        return name;
    }

    /**
     * Is property
     *
     * @param name name
     * @return the boolean
     * @since 2023.1.1
     */
    public static boolean isProperty(String name) {
        return isGetter(name) || isSetter(name);
    }

    /**
     * Is getter
     *
     * @param name name
     * @return the boolean
     * @since 2023.1.1
     */
    public static boolean isGetter(String name) {
        return name.startsWith("get") && name.length() > 3 || name.startsWith("is") && name.length() > 2;
    }

    /**
     * Is setter
     *
     * @param name name
     * @return the boolean
     * @since 2023.1.1
     */
    public static boolean isSetter(String name) {
        return name.startsWith("set") && name.length() > 3;
    }

}

SelectSubsetUtils

该工具类可以实现通过对象的指定字段实现双向遍历

/**
 *  通过本级唯一key值,以及本级字段、父级字段迭查询所有本级的子集
 */
@UtilityClass
public class SelectSubsetUtils {

    /**
     * Filter
     *
     * @param <D>    parameter
     * @param origin 需要被过滤的数据集
     * @param left   本级唯一key -例如code
     * @param right  本级与父级关联key值 -例如parentCode
     * @param adjust 本级唯一key值过滤条件
     * @return the list
     * @since 2023.1.1
     */
    public static <D> List<D> filterSon(List<D> origin, ZhFunction<D, ?> left, ZhFunction<D, ?> right, Adjust adjust) {
        return filter(origin, left, right, adjust, false);
    }


    /**
     * Filter parent
     *
     * @param <D>    parameter
     * @param origin 需要被过滤的数据集
     * @param left   本级唯一key -例如code
     * @param right  本级与父级关联key值 -例如parentCode
     * @param adjust 本级唯一key值过滤条件
     * @return the list
     * @since 2023.1.1
     */
    public static <D> List<D> filterParent(List<D> origin, ZhFunction<D, ?> left, ZhFunction<D, ?> right, Adjust adjust) {
        return filter(origin, left, right, adjust, true);
    }


    /**
     * Filter
     *
     * @param <D>      parameter
     * @param origin   origin
     * @param left     left
     * @param right    right
     * @param adjust   adjust
     * @param reverset reverset
     * @return the list
     * @since 2023.1.1
     */
    private static <D> List<D> filter(List<D> origin, ZhFunction<D, ?> left, ZhFunction<D, ?> right,
                                      Adjust adjust, Boolean reverset) {
        //过滤全量数据按照本级唯一key进行过滤
        List<D> ds = origin.stream()
                .filter(o -> {
                    //通过反射获取到传递进来的本级唯一key值
                    Object value = getObject(left, o);
                    return adjust.test(value);
                }).collect(Collectors.toList());
        //调用与父级关联的key值进行递归过滤
        if (reverset) {
            // 如果是反转,那么就是父级过滤
            return filter(origin, ds, left, right);
        } else {
            // 如果是正常,那么就是子级过滤
            return filter(origin, ds, right, left);
        }
    }


    /**
     * Filter
     *
     * @param <D>    parameter
     * @param origin 需要被过滤的数据源
     * @param filter 被过滤后的数据集
     * @param left   本级唯一key -例如code
     * @param right  本级与父级关联key值 -例如parentCode
     * @return the list
     * @since 2023.1.1
     */
    private static <D> List<D> filter(List<D> origin, List<D> filter, ZhFunction<D, ?> left, ZhFunction<D, ?> right) {
        //构建本级过滤的数据,然后拿出来跟全量数据再次进行比对
        List<D> list = new LinkedList<>(filter);
        if (CollectionUtils.isEmpty(filter)) {
            return list;
        }
        //遍历过滤后的数据集
        filter.forEach(f -> {
            //跟全量的数据进行比较
            List<D> ds = origin.stream()
                    .filter(o -> {
                        //将全量的数据和过滤出的数据进行比较,找出后续的子节点
                        Object value = getObject(left, o);
                        Object value2 = getObject(right, f);
                        return value.equals(value2);
                    }).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(ds)) {
                return;
            }
            //递归调用
            list.addAll(filter(origin, ds, left, right));
        });
        return list;
    }

    /**
     * 获取值
     *
     * @param <D>        parameter
     * @param firstFiled first filed
     * @param d          d
     * @return object object
     * @since 2023.1.1
     */
    private static <D> Object getObject(ZhFunction<D, ?> firstFiled, D d) {
        String lambdaMethodName = ZhLambdaUtils.getLambdaMethodName(firstFiled);
        //获取到字段名称
        String fieldName = ZhLambdaUtils.methodToProperty(lambdaMethodName);
        Object value = null;
        try {
            Field field = FieldUtils.getDeclaredField(d.getClass(), fieldName, true);
            value = field.get(d);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return value;
    }

    /**
     * 自定义判断函数
     */
    @FunctionalInterface
    public interface Adjust {
        /**
         * Test
         *
         * @param value value
         * @return the boolean
         * @since 2023.1.1
         */
        boolean test(Object value);
    }

    /**
     * 自定义 Serializable 函数接口,这个接口有大用,至于为什么可以看下面参考博客
     */
    @FunctionalInterface
    public interface ZhFunction<T, R> extends Function<T, R>, Serializable {
    }

}

测试

寻找字段 Code 为 1681497872765722624,并且关联的父级code为 ParentCode 的所有子集

public static void main(String[] args) {
        List<A> list = new ArrayList<>();
        A a = new A("1", "1681497872765722624");
        A a2 = new A("1681497872765722624", "1681498005196677120");
        A a3 = new A("1681497872765722624", "1681498062989991936");
        A a4 = new A("1681497872765722624", "1681498151091347456");
        A a5 = new A("1681498151091347456", "2");
        A a6 = new A("1681498151091347456", "3");
        A a7 = new A("8", "7");
        A a8 = new A("", "8");
        list.add(a);
        list.add(a2);
        list.add(a3);
        list.add(a4);
        list.add(a5);
        list.add(a6);
        list.add(a7);
        list.add(a8);
        List<A> target = filter(list, A::getCode, A::getParentCode, "1681497872765722624"::equals);
        target.forEach(System.out::println);
}

在这里插入图片描述

参考文档:
函数接口实现Serializable的用处说明

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值