JDFrame 一款比 Java 8 Stream 更灵活的数据处理工具
一、JDFrame 介绍
在大数据处理领域,Apache Spark
以其强大的分布式计算能力和丰富的数据处理API
而广受好评。然而,在许多日常的软件开发场景中,我们面临的数据量可能并不需要Spark
这样的分布式系统来处理。相反,我们更希望有一种工具能够在单机环境下提供类似Spark
的便捷数据处理能力。Java 8
的Stream API
虽然提供了一种简化的数据处理方式,但在复杂的数据转换和操作上,它仍显得有些力不从心。正是在这样的需求背景下,JDFrame
应运而生。JDFrame
借鉴了Spark
的API
设计理念,为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@NoArgsConstructorpublic 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); // 保留 Top5sdf1.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@NoArgsConstructorpublic 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
确实是一个非常好的工具。
比如数据量在一百万的时候,差距明显减少:
下面可以学习下 JDFrame
的 Api
。
三、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);
相关文章:

JDFrame 一款比 Java 8 Stream 更灵活的数据处理工具
一、JDFrame 介绍 在大数据处理领域,Apache Spark以其强大的分布式计算能力和丰富的数据处理API而广受好评。然而,在许多日常的软件开发场景中,我们面临的数据量可能并不需要Spark这样的分布式系统来处理。相反,我们更希望有一种…...

《Android系统开发中高级定制专栏导读》
《Android系统开发中高级定制专栏导读》 欢迎来到【Android系统开发中高级定制‘】专栏!在这里,将深入探讨Android系统开发与定制的方方面面,涵盖从系统接口定制、权限管理、系统应用配置、驱动入门配置等多个领域。无论你是刚接触Android系…...

LeetCode 114. 二叉树展开为链表
更多题解尽在 https://sugar.matrixlab.dev/algorithm 每日更新。 组队打卡,更多解法等你一起来参与哦! LeetCode 114. 二叉树展开为链表,难度中等。 DFS 解题思路:先用 DFS 遍历二叉树,将树的结果存放在 List 中&am…...

78.子集
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 :总 // 注释的都为后来思考不必要的 class Solution {List<List<Integer…...

历史标签如何时间迁移?
本文解析的论文是: Lin, C.; Du, P.; Samat, A.; Li, E.; Wang, X.; Xia, J. Automatic Updating of Land Cover Maps in Rapidly Urbanizing Regions by Relational Knowledge Transferring from GlobeLand30. Remote Sens. 2019, 11, 1397. https://doi.org/10.33…...

Jenkins参数化构建
目录 一. 准备ansible 二. Gitlab新建子项目 三. Jenkins建立任务,进行初步配置 四. 导入nginx主机的公钥 五. 配置ansible执行脚本 六. 构建测试 一. 准备ansible 在jenkins主机中安装ansible [rootjenkins ~]# yum install -y epel-release [rootjenkins…...

函数实例讲解(三)
文章目录 常用的三个数学函数1、绝对值函数ABS2、取整数部分INT3、求余数函数MOD 求极值函数max、min1、Max2、Min 附加条件下求平均数1、AVERAGE2、AVERAGEIF3、AVERAGEIFS VLOOKUP与COLUMN1、VLOOKUP2、COLUMN 查找函数LOOKUP1、基础语法2、向量形式3、数组形式 常用的三个数…...

如何选择适合自己的编程语言?大学新生入门编程最佳路径指南
编程已成为当代大学生的必备技能,但面对众多编程语言和学习资源,新生们常常感到迷茫。如何选择适合自己的编程语言?如何制定有效的学习计划?如何避免常见的学习陷阱?本文将为你提供详细的指导,为你的大学生…...

编程的法则 依赖倒置原则 (Dependency Inversion Principle)包括如何实践
编程的法则 依赖倒置原则 (Dependency Inversion Principle)包括如何实践 flyfish 2017-07-19 2024-07-18 在软件工程中,存在着层次结构,其中上层的业务逻辑依赖于下层的实现细节。如果是直接的依赖关系可能会导致问题…...

[数据集][目标检测]肾结石检测数据集VOC+YOLO格式1299张1类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):1299 标注数量(xml文件个数):1299 标注数量(txt文件个数):1299 标注…...

pxe安装部署
RHEL7为例: ifconfig查看ip 一.环境配置 1.配置软件仓库: mkdir /rhel7 mount /dev/cdrom /rhel7 echo mount /dev/cdrom /rhel74 >> /etc/rc.d/rc,local chmod x /etc/rc.d/rc.local 2.关闭火墙和selinux,下载…...

Linux用户-sudo命令
作者介绍:简历上没有一个精通的运维工程师。希望大家多多关注我,我尽量把自己会的都分享给大家,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 Linux是一个多用户多任务操作系统,这意味着它可以同时支持多个用户登录并使用系统。…...

Unity强化工程 之 SpriteEditer Multiple
本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正 1. SpriteEditer Multiple Automatic slicing - Unity 手册 这是用于裁剪图集的模式 应用之后精灵编辑器会看到Slice亮…...

大数据Flink(一百零九):阿里云Flink的基本名称概念
文章目录 阿里云Flink的基本名称概念 一、层次结构 二、概念说明 1、工作空间(Workspace) 2、项目空间(Namespace) 3、资源(Resource) 4、草稿(Draft&#…...

如何利用AI工具延长摸鱼时间、准点下班?
你好同学,我是沐爸,欢迎点赞、收藏和关注!个人知乎、公众号"沐爸空间" 俗话说,不会摸鱼的程序猿不是好的程序猿。同学,你是不是也在为不能准点下班、每天加班、没有时间提升自己而烦恼? 接下来…...

Yarn:一个快速、可靠且安全的JavaScript包管理工具
(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,还请三连支持一波哇ヾ(@^∇^@)ノ) 目录 一、Yarn简介 二、Yarn的安装 1. 使用npm安装Yarn 2. 在macOS上…...

上线前端系统
上线一个静态的前端系统(续) 在eleme服务器上 启动服务 启动rpcbind [rooteleme-static ~]# systemctl restart rpcbind 启动nfs [rooteleme-static ~]# systemctl restart nfs 重启服务 启动smb [rootstatic-server img]# systemctl start smb…...

制作一个不依赖任何基础镜像的docker镜像
1、比如官方提供的hello-world镜像 #docker pull hello-world #docker images hello-world latest feb5d9fea6a5 2 years ago 13.3kB 可以看到这个镜像只有13.3kB 2、# docker run hello-world 只能打印一些信息 3、这个hello-world镜像的dockerfile就下面3行语…...

【拓扑排序topsort】——启动!!!
B3644 【模板】拓扑排序 / 家谱树 #include<bits/stdc.h> #define int long long #define fi first #define se second #define pb push_back #define PII pair<int,int > #define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std; …...

计算机网络-http协议和https的加密原理
HTTP(HyperText Transfer Protocol,超文本传输协议)是用于在万维网(World Wide Web)上传输超文本的基础协议。它定义了客户端(通常是浏览器)和服务器之间的文本数据传输格式和规则。以下是HTTP的…...

共享`pexlinux`数据文件的网络服务
实验环境准备: 1.红帽7主机 2.要全图形安装 3.配置网络为手动,配置网络可用 4.关闭vmware DHCP功能 一、kickstart自动安装脚本制作 1.安装图形化生成kickstart自动脚本安装工具 2.启动图形制作工具 3.图形配置脚本 这里使用的共享方式是http࿰…...

HC32F4A0 10路串口UART 配置
HC32 小华MCU 使用一段时间了,反正芯片BUG 是比较多了,比如串口接收错误后导致再也无法接收,PWM模块无法输出 低电平 , CAN 接收错误导致 输出引脚 CAN_TXD 一直输出脉冲 。。。;好的一面也存在吧,IO 引脚…...

拯救PyCharm:击退IDE崩溃的终极策略
拯救PyCharm:击退IDE崩溃的终极策略 PyCharm,作为开发界的明星IDE之一,以其强大的功能和灵活的定制性深受广大开发者喜爱。然而,即便是这样一款卓越的开发工具,也可能会遇到崩溃的问题,影响开发效率和工作…...

深入解析Unix命令:掌握wc、whereis和which的使用技巧
目录 1. wc命令 2. whereis命令 3. which命令 结论 在Unix和类Unix系统中,wc、whereis和which是三个常用的命令行工具,每个都有着独特的功能和用途。让我们逐个来了解它们的作用和使用方法。 1. wc命令 wc命令是"word count"的缩写&…...

奥运会大规模使用中国AI大模型!
B站:啥都会一点的研究生公众号:啥都会一点的研究生 AI圈最近又发生了啥新鲜事? 巴黎奥运会大规模使用中国 AI 大模型 巴黎奥运会成为一场科技与体育的盛宴,其中包括了大量中国科技的应用。AI 技术将在多个方面发挥作用…...

Linux中的线程3
死锁 在Linux操作系统中,死锁(Deadlock)是指两个或多个进程(或线程)在执行过程中,因互相持有对方所需的资源而又都在等待对方释放资源,导致它们都无法继续执行下去的一种状态。这种僵局会浪费系…...

内网权限维持——利用WMI进行权限维持
文章目录 一、WMI事件订阅机制简介二、利用事件订阅进行权限维持三、防御方式 一、WMI事件订阅机制简介 WMI(Windows Management Instrumentation,Windows管理规范)是windows提供的一种能够直接与系统进行交互的机制,旨在为系统中…...

【数据结构算法经典题目刨析(c语言)】括号匹配问题(图文详解)
💓 博客主页:C-SDN花园GGbond ⏩ 文章专栏:数据结构经典题目刨析(c语言) 目录 一、题目描述 二、解题思路 三、代码实现 一、题目描述 二、解题思路 问题要求将三种类型括号匹配,其中包括顺序匹配和数量匹配 使用栈的后进先…...

浅谈 Spring AOP框架 (1)
文章目录 一、什么是 Spring AOP二、为什么要使用 Spring AOP三、AOP 的一些应用场景四、AOP 的组成五、如何使用 Spring AOP六、Spring AOP 的实现原理6.1、JDK 和 CGLIB 的区别 一、什么是 Spring AOP AOP (Aspect Oriented Programming) :面向切面编程ÿ…...

Linux 面试准备 - 2024
复习一下,资料来自慕课网课程 Linux 速成班和一些网上面试资料。 1. Linux 内核功能 1. 内存管理 2. 进程管理 3. 设备驱动程序 4. 系统调用和安全防护 2. 文件系统 - 一切皆文件 2.1 文件目录 /根目录etc配置文件bin必要命令usr 二级目录(非用户…...