网易首页 > 网易号 > 正文 申请入驻

Java8 的 Stream 流太难用了?看看 JDFrame

0
分享至

Java精选面试题(微信小程序):5000+道面试题和选择题,真实面经简历模版,包含Java基础、并发、JVM、线程、MQ系列、Redis、Spring系列、Elasticsearch、Docker、K8s、Flink、Spark、架构设计、大厂真题等,在线随时刷题!

0、简介

由于经常记不住stream的一些API每次要复制来复制去并且又长又臭,想要更加语意化的api,于是想到了以前写大数据Spark pandnas 等DataFrame模型时的API, 然后发现其实也存在java的JVM层的DataFrame模型比如 tablesaw,joinery

但是他们得硬编码去指定字段名,这对于有代码洁癖的人实在难以忍受,而且我只是简单统计下数据,我想在一些场景下能不能使用匿名函数去指定的字段处理去处理,于是便有了这个

一个jvm层级的仿DataFrame工具,语意化和简化java8的stream流式处理工具

1、快速开始 1.1、引入依赖


     

 io.github.burukeyou groupId>     

 jdframe artifactId>     

 0.0.2 version> dependency>



1.2、案例

统计每个学校的里学生年龄不为空并且年龄在9到16岁间的合计分数,并且获取合计分前2名的学校

static List studentList =  new ArrayList<>(); static {     studentList.add(new Student(1,"a","一中","一年级",11, new BigDecimal(1)));     studentList.add(new Student(2,"a","一中","一年级",11, new BigDecimal(1)));     studentList.add(new Student(3,"b","一中","三年级",12, new BigDecimal(2)));     studentList.add(new Student(4,"c","二中","一年级",13, new BigDecimal(3)));     studentList.add(new Student(5,"d","二中","一年级",14, new BigDecimal(4)));     studentList.add(new Student(6,"e","三中","二年级",14, new BigDecimal(5)));     studentList.add(new Student(7,"e","三中","二年级",15, new BigDecimal(5))); } // 等价于SQL: // select school,sum(score)   // from students // where age is not null and age >=9 and age <= 16 // group by school // order by sum(score) desc // limit 2 SDFrame > sdf2 = SDFrame.read(studentList)         .whereNotNull(Student::getAge)         .whereBetween(Student::getAge,9,16)         .groupBySum(Student::getSchool, Student::getScore)         .sortDesc(FI2::getC2)         .cutFirst(2); sdf2.show();

输出信息:

c1  c2  三中 10 二中 7 @Data @AllArgsConstructor @NoArgsConstructor publicclass Student {     privateint id;     private String name;     private String school;     private String level;     private Integer age;     private BigDecimal score;     private Integer rank;     public Student(String level, BigDecimal score) {         this.level = level;         this.score = score;     }     public Student(int id, String name, String school, String level, Integer age, BigDecimal score) {         this.id = id;         this.name = name;         this.school = school;         this.level = level;         this.age = age;         this.score = score;     } }
2、API案例
2.1、矩阵信息相关

void show(int n); // 打印矩阵信息到控制台 List   columns();   // 获取矩阵的表头字段名 List   col(Function function) ;   // 获取矩阵某一列值 T head();                   // 获取第一个元素 List   head(int n);          // 获取前n个元素 T tail();                       // 获取最后一个元素 List   tail(int n);            // 获取后n个元素
2.2、筛选相关

SDFrame.read(studentList)         .whereBetween(Student::getAge,3,6) // 过滤年龄在[3,6]岁的         .whereBetweenR(Student::getAge,3,6) // 过滤年龄在(3,6]岁的, 不含3岁         .whereBetweenL(Student::getAge,3,6)      // 过滤年龄在[3,6)岁的, 不含6岁         .whereNotNull(Student::getName) // 过滤名字不为空的数据, 兼容了空字符串''的判断         .whereGt(Student::getAge,3)    // 过滤年龄大于3岁         .whereGe(Student::getAge,3)   // 过滤年龄大于等于3岁         .whereLt(Student::getAge,3)  // 过滤年龄小于3岁的         .whereIn(Student::getAge, Arrays.asList(3,7,8)) // 过滤年龄为3岁 或者7岁 或者 8岁的数据         .whereNotIn(Student::getAge, Arrays.asList(3,7,8)) // 过滤年龄不为为3岁 或者7岁 或者 8岁的数据         .whereEq(Student::getAge,3) // 过滤年龄等于3岁的数据         .whereNotEq(Student::getAge,3) // 过滤年龄不等于3岁的数据         .whereLike(Student::getName,"jay") // 模糊查询,等价于 like "%jay%"         .whereLikeLeft(Student::getName,"jay") // 模糊查询,等价于 like "jay%"         .whereLikeRight(Student::getName,"jay"); // 模糊查询,等价于 like "%jay"
2.3、汇总相关

JDFrame frame = JDFrame.read(studentList); Student s1 = frame.max(Student::getAge);// 获取年龄最大的学生 Integer s2  = frame.maxValue(Student::getAge);      // 获取学生里最大的年龄 Student s3 = frame.min(Student::getAge);// 获取年龄最小的学生 Integer s4  = frame.minValue(Student::getAge);      // 获取学生里最小的年龄 BigDecimal s5 = frame.avg(Student::getAge); // 获取所有学生的年龄的平均值 BigDecimal s6 = frame.sum(Student::getAge); // 获取所有学生的年龄合计 MaxMin s7 = frame.maxMin(Student::getAge);  // 同时获取年龄最大和最小的学生 MaxMin s8 = frame.maxMinValue(Student::getAge);  // 同时获取学生里最大和最小的年龄
2.4、去重相关

原生steam只支持对象去重,不支持按特定字段去重

List std =  null; std = SDFrame.read(studentList).distinct().toLists(); // 根据对象hashCode去重 std = SDFrame.read(studentList).distinct(Student::getSchool).toLists(); // 根据学校名去重 std = SDFrame.read(studentList).distinct(e -> e.getSchool() + e.getLevel()).toLists(); // 根据学校名拼接级别去重复 std =SDFrame.read(studentList).distinct(Student::getSchool).distinct(Student::getLevel).toLists(); // 先根据学校名去除重复再根据级别去除重复
2.5、简单分组聚合相关

类似sql的 group by语义 简化处理分组和聚合的逻辑, 如果用原生stream需要写可能一大串逻辑。

JDFrame frame = JDFrame.from(studentList); // 等价于 select school,sum(age) ... group by school List > a = frame.groupBySum(Student::getSchool, Student::getAge).toLists(); // 等价于 select school,max(age) ... group by school List > a2 = frame.groupByMaxValue(Student::getSchool, Student::getAge).toLists(); //  与 groupByMaxValue 含义一致,只是返回的是最大的值对象 List > a3 = frame.groupByMax(Student::getSchool, Student::getAge).toLists(); // 等价于 select school,min(age) ... group by school List > a4 = frame.groupByMinValue(Student::getSchool, Student::getAge).toLists(); // 等价于 select school,count(*) ... group by school List > a5 = frame.groupByCount(Student::getSchool).toLists(); // 等价于 select school,avg(age) ... group by school List > a6 = frame.groupByAvg(Student::getSchool, Student::getAge).toLists(); // 等价于 select school,sum(age),count(age) group by school List > a7 = frame.groupBySumCount(Student::getSchool, Student::getAge).toLists(); // (二级分组)等价于 select school,level,sum(age),count(age) group by school,level List > a8 = frame.groupBySum(Student::getSchool, Student::getLevel, Student::getAge).toLists(); // (三级分组)等价于 select school,level,name,sum(age),count(age) group by school,level,name List > a9 = frame.groupBySum(Student::getSchool, Student::getLevel, Student::getName, Student::getAge).toLists();
2.6、排序相关

简化原生stream的排序方式,直接指定字段即可,不用使用Comparator还要去关注升序还是降序

// 等价于 order by age desc SDFrame.read(studentList).sortDesc(Student::getAge); //  等价于 order by age desc, level asc SDFrame.read(studentList).sortDesc(Student::getAge).sortAsc(Student::getLevel); // 等价于 order by age asc SDFrame.read(studentList).sortAsc(Student::getAge); // 使用Comparator 排序 SDFrame.read(studentList).sortAsc(Comparator.comparing(e -> e.getLevel() + e.getId()));
2.7、连接矩阵相关

API列表

append(T t);                    // 等价于集合 add union(IFrame other);          //  等价于集合 addAll join(IFrame other, JoinOn on, Join join);    // 等价于 sql内连接 leftJoin(IFrame other, JoinOn on, Join join);    // 等价于sql左连接,如果左连接失败,K值为null,需手动判断 rightJoin(IFrame other, JoinOn on, Join join);     // 等价于sql右连接,如果右连接失败,T值为null,需手动判断

内连接例子:

System.out.println("======== 矩阵1 ======="); SDFrame sdf = SDFrame.read(studentList); sdf.show(20); // 获取学生年龄在9到16岁的学学校合计分数最高的前10名 SDFrame > sdf2 = SDFrame.read(studentList)         .whereNotNull(Student::getAge)         .whereBetween(Student::getAge,9,16)         .groupBySum(Student::getSchool, Student::getScore)         .sortDesc(FI2::getC2)         .cutFirst(10); System.out.println("======== 矩阵2 ======="); sdf2.show(); SDFrame frame = sdf.join(sdf2, (a, b) -> a.getSchool().equals(b.getC1()), (a, b) -> {     UserInfo userInfo = new UserInfo();     userInfo.setKey1(a.getSchool());     userInfo.setKey2(b.getC2().intValue());     userInfo.setKey3(String.valueOf(a.getId()));     return userInfo; }); System.out.println("======== 连接后结果 ======="); frame.show(5);

打印信息:

======== 矩阵1 ======= id name school level age score rank  1  a    一中     一年级   111           2  a    一中     一年级   111           3  b    一中     一年级   122           4  c    二中     一年级   133           5  d    二中     一年级   144           6  e    三中     二年级   145           7  e    三中     二年级   155           ======== 矩阵2 ======= c1 c2  三中 10 二中 7 一中 4 ======== 连接后结果 ======= key1 key2 key3 key4  一中   4    1          一中   4    2          一中   4    3          二中   7    4          二中   7    5   

类似于

select a.*,b.* from sdf a inner join sdf2 b on  a.school = b.c1
2.8、其他

百分数转换

// 等价于 select round(score*100,2) from student SDFrame map2 = SDFrame.read(studentList).mapPercent(Student::getScore, Student::setScore, 2);

分区

将每个5个元素分成一个小集合,用于将大任务拆成小任务

List > t = SDFrame.read(studentList).partition( 5).toLists();

生成序号

按照age排序,然后根据当前顺序生成排序号到rank字段 (序号从0开始)

SDFrame.read(studentList)     .sortDesc(Student::getAge)     .addSortNoCol(Student::setRank)     .show(30);

输出信息:

id name school level age score rank  7  e    三中     二年级   15  5     0     5  d    二中     一年级   14  4     1     6  e    三中     二年级   14  5     2     4  c    二中     一年级   13  3     3     3  b    一中     三年级   12  2     4     1  a    一中     一年级   11  1     5     2  a    一中     一年级   11  1     6   

生成排名号

按照age降序排序,然后根据当前顺序生成排名号到rank字段 (排名从0开始)

与序号不同的是, 排名是如果值相同认为排名一样。

SDFrame df = SDFrame.read(studentList).addRankingSameColDesc(Student::getAge, Student::setRank); df.show(20);

输出信息

id name school level age score rank  7  e    三中     二年级   15  5     1     5  d    二中     一年级   14  4     2     6  e    三中     二年级   14  5     2     4  c    二中     一年级   13  3     3     3  b    一中     一年级   12  2     4     1  a    一中     一年级   11  1     5     2  a    一中     一年级   11  1     5    

补充条目

1、补充缺失的学校条目

// 所有需要的学校条目 List allDim = Arrays.asList( "一中","二中","三中","四中"); // 根据学校字段和allDim比较去补充缺失的条目, 缺失的学校按照ReplenishFunction生成补充条目作为结果一起返回 SDFrame.read(studentList).replenish(Student::getSchool,allDim,(school) -> new Student(school)).show();

输出

id name school level age score rank  1  a    一中     一年级   11  1           2  a    一中     一年级   11  1           3  b    一中     一年级   12  2           4  c    二中     一年级   13  3           5  d    二中     一年级   14  4           6  e    三中     二年级   14  5           7  e    三中     二年级   15  5           0       四中  

2、分组补充组内缺失的条目

按照学校进行分组, 汇总所有年级allDim. 然后与allDim比较补充每个分组内缺失的年级,缺失的年级按照ReplenishFunction生成补充条目

SDFrame.read(studentList).replenish(Student::getSchool,Student::getLevel,(school,level) -> new Student(school,level)).show(30);

输出

id name school level age score rank  1  a    一中     一年级   111           2  a    一中     一年级   111           3  b    一中     三年级   122           0       一中     二年级                   4  c    二中     一年级   133           5  d    二中     一年级   144           0       二中     三年级                   0       二中     二年级                   6  e    三中     二年级   145           7  e    三中     二年级   155           0       三中     一年级                   0       三中     三年级 

应用场景举例:要求计算近两年每个月的数据,但是数据的年月可能不全,这时就补充缺失的年月数据作为结果一起返回。

最后

代码地址:

https://github.com/burukeYou/JDFrame

Maven依赖地址:

https://central.sonatype.com/artifact/io.github.burukeyou/jdframe

提供了两种Frame,SDFrame和JDFrame 在API层面一模一样, 区别是JDFrame的所有操作实时生效, 无需要重新read生成,而SDFrame与stream流一致,只有执行终止操作才会生效,并且需要重新read生成流, 而且在同一个流之间的操作是互相影响的。

如果只是需要流式操作一条流执行完就用SDFrame, 如果需要“中间站点”数据,然后从“中间站点数据“开始计算就用JDFrame, 这个在含义层面与DataFrame模型类似。

这个在语法层面能实现的矩阵还是比较有限的因为行列是通过枚举的几个FI去描述,但是不同的逻辑导致的矩阵变换的变化可能是非常大的,除非JDK能语法层面支持到吧或者放弃强类型全部硬编码才能实现各种矩阵的表示和变换。期待JDK一个JVM层面的“pandans” 出现。

还有一些api没有列举出来使用的比较少

主要是对逻辑的封装和语意化,如果还有哪些逻辑和api可以扩展可以在评论区留下你的想法。

来源:https://juejin.cn/post/7356652717392740404

公众号“Java精选”所发表内容注明来源的,版权归原出处所有(无法查证版权的或者未注明出处的均来自网络,系转载,转载的目的在于传递更多信息,版权属于原作者。如有侵权,请联系,笔者会第一时间删除处理!

最近有很多人问,有没有技术或摸鱼交流群!加入方式很简单,公众号Java精选,回复“加群”,即可入群!在线摸鱼:https://www.yoodb.com/

文章有帮助的话,点在看,转发吧!

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
这该死的文明——以色列法院驳回加沙儿童入境接受救命治疗的申请

这该死的文明——以色列法院驳回加沙儿童入境接受救命治疗的申请

老王说正义
2026-02-11 23:32:06
贵阳一公司把刮刮乐当开单奖,员工随手一刮中30万元,当事人:将作为孩子的教育基金

贵阳一公司把刮刮乐当开单奖,员工随手一刮中30万元,当事人:将作为孩子的教育基金

黄河新闻网吕梁频道
2026-02-11 10:19:05
上海七莘路和黎安路附近发生塌陷,11日曾因在建地铁项目局部渗漏紧急抢险;闵行区政府:无人员伤亡

上海七莘路和黎安路附近发生塌陷,11日曾因在建地铁项目局部渗漏紧急抢险;闵行区政府:无人员伤亡

大风新闻
2026-02-12 16:17:08
31岁安徽农村小伙迎娶“00后”埃及姑娘:社交平台认识,备了3万元彩礼和3万元首饰

31岁安徽农村小伙迎娶“00后”埃及姑娘:社交平台认识,备了3万元彩礼和3万元首饰

扬子晚报
2026-02-12 11:00:07
杨兰兰不认罪

杨兰兰不认罪

蓝钻故事
2026-02-11 16:19:23
纽约时报:不要相信那些把中国大学排在第一位的排名

纽约时报:不要相信那些把中国大学排在第一位的排名

朗威谈星座
2026-02-12 08:13:40
59岁宋祖英现身活动状态惊艳!短发利落大气,黑色套装优雅端庄

59岁宋祖英现身活动状态惊艳!短发利落大气,黑色套装优雅端庄

琴声飞扬
2026-02-12 11:51:25
大风追踪 | “母亲派出所遭民警责骂,男子插话后被拖进女厕群殴”,终审维持原判,涉案民辅警刑罚不变

大风追踪 | “母亲派出所遭民警责骂,男子插话后被拖进女厕群殴”,终审维持原判,涉案民辅警刑罚不变

大风新闻
2026-02-12 11:43:13
罕见!6名共和党议员“倒戈”,反对特朗普

罕见!6名共和党议员“倒戈”,反对特朗普

扬子晚报
2026-02-12 12:29:06
恶毒!网传广东一婚车被横幅拦截,“新郎不是我,但新娘爱过我”

恶毒!网传广东一婚车被横幅拦截,“新郎不是我,但新娘爱过我”

火山詩话
2026-02-11 15:59:03
炸裂!环卫工时薪3块,却成连轴转牛马,戴“电子镣铐”提醒工作

炸裂!环卫工时薪3块,却成连轴转牛马,戴“电子镣铐”提醒工作

社会酱
2026-02-12 17:28:57
上海宝冶集团被暂停全军采购资格

上海宝冶集团被暂停全军采购资格

地产微资讯
2026-02-12 16:12:33
顶格重罚!半导体设备巨头对华“违规”出口,被罚2.52亿美元!

顶格重罚!半导体设备巨头对华“违规”出口,被罚2.52亿美元!

EETOP半导体社区
2026-02-12 12:07:52
中芯国际这次真够抢风头的

中芯国际这次真够抢风头的

蔚然先声
2026-02-12 08:33:06
商家称新娘穿脏敬酒服,竟“焊接”吊牌退货!商家:不知道你嫁得好不好,但路一定不好走……

商家称新娘穿脏敬酒服,竟“焊接”吊牌退货!商家:不知道你嫁得好不好,但路一定不好走……

扬子晚报
2026-02-12 07:35:48
重赛仍不满?荷兰名将拒接受中国选手道歉:毫无意义!铜牌被抢走

重赛仍不满?荷兰名将拒接受中国选手道歉:毫无意义!铜牌被抢走

我爱英超
2026-02-12 05:13:01
谢贤前女友又曝猛料!谢霆锋娶张柏芝并不是因为爱她,隐瞒所有人

谢贤前女友又曝猛料!谢霆锋娶张柏芝并不是因为爱她,隐瞒所有人

洲洲影视娱评
2026-02-12 12:26:45
高市发言仅72小时,特朗普急了,白宫罕见出手,欧韩日集体反击

高市发言仅72小时,特朗普急了,白宫罕见出手,欧韩日集体反击

策略述
2026-02-11 19:12:07
罗永浩怼段永平“懂个屁”,这个全是“破烂”的时代

罗永浩怼段永平“懂个屁”,这个全是“破烂”的时代

不正确
2026-02-11 22:53:03
关门14年,广州知名百年老字号重开!街坊激动哭了:必须支持

关门14年,广州知名百年老字号重开!街坊激动哭了:必须支持

羊城攻略
2026-02-12 04:39:35
2026-02-12 18:04:49
Java精选
Java精选
一场永远也演不完的戏
1772文章数 3859关注度
往期回顾 全部

科技要闻

10倍速的一夜:三大模型春节前的暗战

头条要闻

母亲派出所遭警察责骂 男子插话后被拖进女厕群殴

头条要闻

母亲派出所遭警察责骂 男子插话后被拖进女厕群殴

体育要闻

31岁首次参加冬奥,10年前她是个水管工

娱乐要闻

体操运动员坠楼涉事教练被立案调查

财经要闻

“影子万科”如何掘金万科?

汽车要闻

开212 T01柴油版去穿越 连牧马人都跟不上

态度原创

本地
旅游
教育
公开课
军事航空

本地新闻

下一站是嘉禾望岗,请各位乘客做好哭泣准备

旅游要闻

“西夏区贺兰山东麓户外运动线路”入选2026年春节假期户外运动精品线路

教育要闻

雅思6.5分到底啥水平?一篇讲明白

公开课

李玫瑾:为什么性格比能力更重要?

军事要闻

特朗普:若美伊谈判失败 或再派一支航母打击群

无障碍浏览 进入关怀版