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的用处说明

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/144527.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode】挑战100天 Day11(热题+面试经典150题)

【LeetCode】挑战100天 Day11&#xff08;热题面试经典150题&#xff09; 一、LeetCode介绍二、LeetCode 热题 HOT 100-132.1 题目2.2 题解 三、面试经典 150 题-133.1 题目3.2 题解 一、LeetCode介绍 LeetCode是一个在线编程网站&#xff0c;提供各种算法和数据结构的题目&…

Mybatis中limit用法补充

limit a,b a是从第a1条数据开始&#xff0c;b是指读取几条数据 例如&#xff1a;select * from table limit 0,10 这句sql语句是说从表中获取第1条开始的10条记录 前端将page:页码    pageSize:每页多少条    这两个参数&#xff0c;传到后台。    通过这两个参数&am…

实力爆发 | 国民品牌大运新能源亮相广州车展

2023第二十一届广州国际汽车展览会将于11月17日至26日在广州琶洲广交会展馆拉开大幕&#xff0c;本届广州车展以“新科技新生活”为主题&#xff0c;将汇集国内外车企的多款重磅新车及前沿新能源出行技术。 &#xff08;2023广州国际汽车展览会&#xff09; 随着环保意识的提高…

个人类型小程序已支持申请微信认证

小程序申请微信认证 政府、媒体、其他组织类型账号&#xff0c;必须通过微信认证验证主体身份。企业类型账号&#xff0c;可以根据需要确定是否申请微信认证。已认证账号可使用微信支付权限。 个人类型小程序已支持微信认证&#xff08;审核大约需要1-3个工作日&#xff09; …

Unity中Shader的矩阵加减法

文章目录 前言一、什么是矩阵矩阵就是一组数的阵列 二、矩阵的加法三、矩阵的负值四、矩阵的减法五、矩阵的表示 前言 Unity中Shader用到的矩阵加减法&#xff0c;以及矩阵的一些基础常识 一、什么是矩阵 矩阵就是一组数的阵列 1 2 3 4 5 6 二、矩阵的加法 两个矩阵相加就是…

专题解读|Graph Fairness代表性工作介绍

1. 图上的公平性问题 图在现实世界中无处不在&#xff0c;例如知识图谱&#xff0c;社交网络和生物网络。近年来&#xff0c;图神经网络( graph neural networks&#xff0c;GNNs ) 在图结构数据建模方面表现出了强大的能力。一般地&#xff0c;GNNs采用消息传递机制&#xff…

SOME/IP学习笔记3

目录 1.SOMEIP Transformer 1.1 SOME/IP on-wire format 1.2 协议指定 2. SOMEIP TP 2.1 SOME/IP TP Header 3.小结 1.SOMEIP Transformer 根据autosar CP 相关规范&#xff0c;SOME/IP Transformer主要用于将SOME/IP格式的数据序列化&#xff0c;相当于一个转换器。总体…

Cesium 展示——绘制圆的几种方式

文章目录 需求分析需求 总结绘制圆的几种方式 分析 使用圆形几何体(CircleGeometry):var circle = viewer.entities.add({position: Cesium.Cartesian3.fromDegrees

七个合法学习黑客技术的网站,让你从萌新成为大佬

大家好我是若风&#xff0c;一个8年网络安全攻防经验的白帽黑客。 合法的学习网站&#xff0c;以下这些网站&#xff0c;虽说不上全方位的满足你的需求&#xff0c;但是大部分也都能。能带你了解到黑客有关的技术&#xff0c;视频&#xff0c;电子书&#xff0c;实践&#xff0…

Git 安装配置

目录 Linux 平台上安装 Debian/Ubuntu Centos/RedHat 源码安装 Windows 平台上安装 Mac 平台上安装 Git 配置 用户信息 文本编辑器 差异分析工具 查看配置信息 在使用Git前我们需要先安装 Git。Git 目前支持 Linux/Unix、Solaris、Mac和 Windows 平台上运行。 Git …

AR人脸道具SDK,打造极致用户体验

为了满足企业在AR领域的应用需求&#xff0c;美摄科技推出了一款领先的AR人脸道具SDK&#xff0c;旨在帮助企业快速、高效地开发出具有丰富玩法体验的AR应用&#xff0c;从而提升企业的竞争力和市场份额。 一、丰富的AR人脸道具&#xff0c;满足多样化需求 美摄科技AR人脸道具…

【Python图像超分】Real-ESRGAN图像超分模型(超分辨率重建)详细安装和使用教程

1 前言 图像超分是一种图像处理技术&#xff0c;旨在提高图像的分辨率&#xff0c;使其具有更高的清晰度和细节。这一技术通常用于图像重建、图像恢复、图像增强等领域&#xff0c;可以帮助我们更好地理解和利用图像信息。图像超分技术可以通过多种方法实现&#xff0c;包括插值…

ebSocket connection to ‘wss://xxx.xxxxxxx.xxx/‘ failed:

目录 1&#xff1a;网络连接问题&#xff1a;检查您是否已连接到互联网&#xff0c;您的网络是否稳定。您还可以尝试重置您的Internet连接或切换到另一个网络。 排除方法&#xff1a;直接打开个网址就知道了&#xff0c;这应该不用教了吧 2&#xff1a;防火墙或代理设置&…

Postgresql数据类型-数据类型转换

PostgreSQL数据类型转换主要有三种方式&#xff1a;通过格式化函数、CAST函数、::操作符&#xff0c;下面分别介绍。 通过格式化函数进行转换 PostgreSQL提供一系列函数用于数据类型转换&#xff0c;如表所示。 通过CAST函数进行转换将varchar字符类型转换成text类型&#xf…

JavaScript基础入门05

目录 1.操作结点 1.1新增节点 1.1.1. 创建元素节点 1.1.2. 插入节点到 dom 树中 1.2删除节点 2.代码案例: 猜数字 2.1预期效果 2.2代码实现 3.代码案例: 表白墙 3.1预期效果 3.2创建页面布局 3.3调整样式 3.4实现提交 3.5实现点击按钮的动画效果 4.代码案例: 待办…

简单描述下微信小程序的相关文件以及类型?

目录 前言 相关文件类型 1. JSON 配置文件 2. WXML 文件 3. WXSS 文件 4. JavaScript 文件 图片、音频、视频等资源文件 小程序配置文件&#xff08;project.config.json&#xff09; 理解 优缺点 优点&#xff1a; 缺点&#xff1a; 总结 结尾 前言 微信小程序…

Live800:高效工作,客服人必学的10种时间效率管理术

客服人员是企业与客户沟通的桥梁&#xff0c;需要在繁忙的工作环节中保持高效率。只有提高时间效率才能更好地服务客户&#xff0c;满足客户的需求&#xff0c;提升客户满意度。因此&#xff0c;客服人员需要掌握时间效率管理术来提高工作效率。 1、制定工作计划 在开始工作之…

C# DirectoryInfo类的用法

在C#中&#xff0c;DirectoryInfo类是System.IO命名空间中的一个类&#xff0c;用于操作文件夹&#xff08;目录&#xff09;。通过DirectoryInfo类&#xff0c;我们可以方便地创建、删除、移动和枚举文件夹。本文将详细介绍DirectoryInfo类的常用方法和属性&#xff0c;并提供…

车间安灯呼叫看板的功能与优势介绍

现在的工厂车间的管理变得越来越复杂&#xff0c;生产过程中可能会出现各种问题&#xff0c;如设备故障、物料短缺、工人伤病等。为了提高生产效率、优化生产管理&#xff0c;许多工厂引入了车间安灯呼叫看板系统。本文将介绍车间安灯呼叫看板的功能与优势。 一、功能介绍 1. 实…

图像实验室搭建

#搭建一个简单的图像实验室#&#xff0c;满足中低端camera产品的调试和测试需求。 目录 &#xff08;1&#xff09;实验室的功能 &#xff08;2&#xff09;实验室的设备 1、光源 2、图卡 3、辅助设备&#xff08;升级&#xff09; &#xff08;3&#xff09;实验室的布…