当前位置: 首页 > news >正文

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

一、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@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 确实是一个非常好的工具。

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

在这里插入图片描述

下面可以学习下 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);

相关文章:

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

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

《Android系统开发中高级定制专栏导读》

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

LeetCode 114. 二叉树展开为链表

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

78.子集

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

历史标签如何时间迁移?

本文解析的论文是&#xff1a; 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建立任务&#xff0c;进行初步配置 四. 导入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、数组形式 常用的三个数…...

如何选择适合自己的编程语言?大学新生入门编程最佳路径指南

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

编程的法则 依赖倒置原则 (Dependency Inversion Principle)包括如何实践

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

[数据集][目标检测]肾结石检测数据集VOC+YOLO格式1299张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1299 标注数量(xml文件个数)&#xff1a;1299 标注数量(txt文件个数)&#xff1a;1299 标注…...

pxe安装部署

RHEL7为例&#xff1a; ifconfig查看ip 一.环境配置 1.配置软件仓库&#xff1a; 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&#xff0c;下载…...

Linux用户-sudo命令

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

Unity强化工程 之 SpriteEditer Multiple

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

大数据Flink(一百零九):阿里云Flink的基本名称概念

文章目录 阿里云Flink的基本名称概念 一、层次结构 二、​​​​​​​​​​​​​​概念说明 1、工作空间&#xff08;Workspace&#xff09; 2、项目空间&#xff08;Namespace&#xff09; 3、资源&#xff08;Resource&#xff09; 4、草稿&#xff08;Draft&#…...

如何利用AI工具延长摸鱼时间、准点下班?

你好同学&#xff0c;我是沐爸&#xff0c;欢迎点赞、收藏和关注&#xff01;个人知乎、公众号"沐爸空间" 俗话说&#xff0c;不会摸鱼的程序猿不是好的程序猿。同学&#xff0c;你是不是也在为不能准点下班、每天加班、没有时间提升自己而烦恼&#xff1f; 接下来…...

Yarn:一个快速、可靠且安全的JavaScript包管理工具

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;还请三连支持一波哇ヾ(&#xff20;^∇^&#xff20;)ノ&#xff09; 目录 一、Yarn简介 二、Yarn的安装 1. 使用npm安装Yarn 2. 在macOS上…...

上线前端系统

上线一个静态的前端系统&#xff08;续&#xff09; 在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&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是用于在万维网&#xff08;World Wide Web&#xff09;上传输超文本的基础协议。它定义了客户端&#xff08;通常是浏览器&#xff09;和服务器之间的文本数据传输格式和规则。以下是HTTP的…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析

今天聊的内容&#xff0c;我认为是AI开发里面非常重要的内容。它在AI开发里无处不在&#xff0c;当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗"&#xff0c;或者让翻译模型 "将这段合同翻译成商务日语" 时&#xff0c;输入的这句话就是 Prompt。…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机&#xff0c;点进去 点进去 查看URL&#xff0c;有 ?fileflag.php说明存在文件包含&#xff0c;原理是php://filter 协议 当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执行。 用php://filter加编码&#xff0c;能让PHP把文件内容…...