前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >JDK24:Stream流有个大变化,用起来更爽了

JDK24:Stream流有个大变化,用起来更爽了

作者头像
大风写全栈
发布2025-02-21 13:21:30
发布2025-02-21 13:21:30
4300
代码可运行
举报
文章被收录于专栏:锤子代码锤子代码
运行总次数:0
代码可运行

刁钻的需求

有个领导叫老溜,我们叫他老六。

安排了这样一个需求,数据库返回来源不明的一串数字。

需要将这些数字两个分一组输出。

老六还画了个图,大概说了一下。

比如数据库返回的是:[0,1,2,3,4,5,6,7,8,9]

我们需要实现的效果是: [[0,1],[2,3],[4,5],[6,7],[8,9]]

意思明白了,下面就着手实现。

没有流收集器但有流

轻松就写了下面这一堆代码。

代码语言:javascript
代码运行次数:0
复制
    List<Integer> numbers = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
    Map<Integer, List<Integer>> result =
        numbers.stream()
            // 按索引分组
            .collect(
                Collectors.groupingBy(
                    // 每两个元素为一组(0-1, 2-3, ...)
                    i -> i / 2,
                    // 映射原始数组元素到分组中
                    Collectors.mapping(
                        numbers::get,
                        // 收集为列表
                        Collectors.toList())));

    // 输出 [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]
    System.out.println(result.values());

说能用勉强也能将就,但现在有更好的选择了。

关于流收集器

JEP 485扩展了 Java 的 Stream API,允许开发者通过自定义中间操作(称为“收集器”)实现更灵活、更具表现力的数据处理。主要改进包括:

  1. 支持定义复杂的数据转换操作(如窗口分组、去重等);
  2. 兼容顺序流和并行流;
  3. 提供与现有流操作一致的 API 设计。

简而言之就是,现在可以在流的中间增加自定义操作(有几个的内置收集器),方便使用,提高效率。

使用流收集器重写一下

改写后如下:

代码语言:javascript
代码运行次数:0
复制
List<List<Integer>> result =
        Stream.iterate(0, i -> i + 1)
            .limit(10)
            .gather(Gatherers.windowFixed(2))
            .toList();

是不是简洁多了?

内置的流收集器

官方内置了如下5个流收集器:

1. fold:一个有状态的多对一收集器,以增量方式构造聚合。

有状态的多对一收集器,以增量方式构造聚合结果(如累加),最终输出单一聚合值。

fold 将流元素逐个累加,初始值为 0,最终输出总和。

代码语言:javascript
代码运行次数:0
复制
Stream.of(1, 2, 3, 4, 5)
        .gather(Gatherers.fold(() -> 0, Integer::sum))
        .forEach(System.out::println);
// 输出: 15

2. mapConcurrent:一个有状态的一对一收集器,同时为每个元素调用函数,直到达到限制。

每个元素乘以2:

代码语言:javascript
代码运行次数:0
复制
 Stream.iterate(0, i -> i + 1)
        .limit(5)
        .gather(Gatherers.mapConcurrent(3, (a) -> a * 2))
        .forEach(System.out::println);
/* 
输出:
0
2
4
6
8 
*/ 

并发处理每个元素,并保持顺序。

3. scan:有状态的一对一收集器,应用函数到当前状态和元素生成下一个元素。

计算累积阶乘(1→2→6→24→120)。

代码语言:javascript
代码运行次数:0
复制
Stream.iterate(1, i -> i + 1)
        .limit(5)
        .gather(Gatherers.scan(() -> 1, (acc, i) -> acc * i))
        .forEach(System.out::println);
// 输出: 1, 2, 6, 24, 120  

4. windowFixed:多对多收集器,将元素分组到固定大小的窗口,满时发射。

每3个元素为一组,输出子列表。

代码语言:javascript
代码运行次数:0
复制
Stream.iterate(0, i -> i + 1)
        .limit(8)
        .gather(Gatherers.windowFixed(3))
        .forEach(System.out::println);
// 输出: [0,1,2], [3,4,5], [6,7]  

5. windowSliding:多对多收集器,滑动窗口,每个窗口删除第一个元素,添加下一个。

窗口大小为3,每次滑动一位(如从[0,1,2]到[1,2,3])。

代码语言:javascript
代码运行次数:0
复制
Stream.iterate(0, i -> i + 1)
        .limit(8)
        .gather(Gatherers.windowSliding(3))
        .forEach(System.out::println);
// 输出: [0,1,2], [1,2,3], [2,3,4], [3,4,5], [4,5,6], [5,6,7]  

常用的方式总结

  • fold 和 scan 用于聚合计算,前者输出单一结果,后者生成中间状态序列。
  • mapConcurrent 限制处理元素数量,适用于资源敏感场景。
  • windowFixed 和 windowSliding 支持滑动窗口操作,适用于时间序列分析或分块处理。

学会了吗?

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-02-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 锤子代码 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档