Loading [MathJax]/jax/input/TeX/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java8 Stream流的终端操作

Java8 Stream流的终端操作

作者头像
喜欢天文的pony站长
发布于 2020-10-09 07:31:02
发布于 2020-10-09 07:31:02
73600
代码可运行
举报
文章被收录于专栏:RabbitMQ实战RabbitMQ实战
运行总次数:0
代码可运行
  • Java8提供的Stream支持两种操作
    • 一种是中间操作,如filter, map, skip, limit...
    • 另外一种是终端操作,如count, findFirst, forEach和reduce...

中间操作不会消耗流,只是将一个流转换成另外一个流,类似于流水线。

终端操作会消耗流,以产生一个最终结果,终端操作完成后,流就被消耗了,不可再调用相关操作流的方法。

  • Collectors预定义好的部分终端操作

Collectors终端操作

一、 规约与汇总

1. 查找流中的最大值和最小值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static void main(String[] args) {
    Random random = new Random();
    Optional<Integer> minVal = Stream.generate(() -> random.nextInt(1000))
            .limit(100)
            .collect(Collectors.minBy(Comparator.comparingInt(x -> x)));

    minVal.ifPresent(System.out::println);

    Optional<Integer> maxVal = Stream.generate(() -> random.nextInt(1000))
            .limit(100)
            .collect(Collectors.maxBy(Comparator.comparingInt(x -> x)));
    maxVal.ifPresent(x -> System.out.println("生成的最大随机值为: " + x));

    //或或或或或或或或或或或或或或或或或或或或
    Optional<Integer> maxVal2 = Stream.generate(() -> random.nextInt(1000))
            .limit(100)
            .max(Comparator.comparingInt(x -> x));
}

2. 求和,计算平均值与结果收集器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void sumAvg() {
    Random random = new Random();
    // 生成1000范围内的数字的方法
    Supplier<Integer> integerSupplier = () -> random.nextInt(1000);
    // 生成1000个1000以内的数字,并返回一个列表
    List<Integer> integerList = Stream.generate(integerSupplier)
            .limit(1000)
            .collect(Collectors.toList());

    // 求和操作
    Integer sum = integerList.stream()
            .collect(Collectors.summingInt(x -> x));
    System.out.println("求和结果: " + sum);

    // 计算平均值操作
    Double avg = integerList.stream()
            .collect(Collectors.averagingDouble(x -> x));
    System.out.println("平均值为: " + avg);
}
  • 结果:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
求和结果: 514905
平均值为: 514.905
  • 在需要同时获取流中元素的个数,求和,平均值,最大值,最小值时,可使用收集器XxxSummaryStatistics
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
DoubleSummaryStatistics summaryStatistics = integerList.stream()
        .collect(Collectors.summarizingDouble(x -> x));

long count = summaryStatistics.getCount();
double average = summaryStatistics.getAverage();
double max = summaryStatistics.getMax();
double min = summaryStatistics.getMin();
double sumResult = summaryStatistics.getSum();

System.out.println(count);
System.out.println(average);
System.out.println(max);
System.out.println(min);
System.out.println(sumResult);
// XxxSummaryStatistics重写了toString()方法
System.out.println(summaryStatistics);
  • 结果:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1000
514.905
999.0
0.0
514905.0
DoubleSummaryStatistics{count=1000, sum=514905.000000, min=0.000000, average=514.905000, max=999.000000}

3. 连接并返回字符串Collectors.join(delimiter)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void joinDemo() {
    AppleStream chinaApple = new AppleStream(10, "中国");
    AppleStream usApple = new AppleStream(20, "米国");
    AppleStream koreaApple = new AppleStream(30, "韩国");

    String joinResult = Stream.of(chinaApple, usApple, koreaApple)
            // 需要将流转换成Stream<String>
            .map(AppleStream::toString)
            .collect(Collectors.joining(",", "【", "】"));
    System.out.println(joinResult);

    System.out.println(IntStream.rangeClosed(1, 20)
            .mapToObj(String::valueOf)
            .collect(Collectors.joining(",", "", "")));
}
  • 结果
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
【AppleStream(weight=10, country=中国),AppleStream(weight=20, country=米国),AppleStream(weight=30, country=韩国)1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20

4. 自定义规约操作:广义上的规约汇总

  • Collectors.reducing(U identity, Function<? super T, ? extends U> mapper, BinaryOperator<U> op)
    • 参数U identity 规约起始值,当流中没有元素时也会返回这个值。
    • 参数Function<? super T, ? extends U> mapper 在执行参数3方法之前对流中的元素进行的操作。
    • 参数BinaryOperator<U> opR apply(T t, U u),接收两个参数,并返回经过处理之后的值。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void reduceDemo() {
    Apple chinaApple = new Apple(10, "中国");
    Apple usApple = new Apple(20, "米国");
    Apple koreaApple = new Apple(30, "韩国");

    //重量最大的苹果
    Optional<Apple> maxWeightApple = Stream.<Apple>of(chinaApple, usApple, koreaApple)
            .collect(Collectors.reducing((x1, x2) -> x1.getWeight() > x1.getWeight() ? x1 : x2));
    maxWeightApple.ifPresent(System.out::println);

    // 最小的重量
    Integer minVal = Stream.of(chinaApple, usApple, koreaApple)
            .collect(Collectors.reducing(0, Apple::getWeight, Integer::min));
    System.out.println(minVal);

    // 质量总和
    Integer sumVal = Stream.of(chinaApple, usApple, koreaApple)
            .collect(Collectors.reducing(0, Apple::getWeight, Integer::sum));
    System.out.println(sumVal);
}

二、 分组

  • Collectors.groupingBy() 1. 分组
    • demo(一级分组): 根据规则 质量<=20为优秀,质量>20为一般 将apple进行分组。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

/**
 * 质量标准
 */
enum Quality {
    /**
     * 上乘
     */
    PERFECT,
    /**
     * 普通
     */
    NORMAL;
}

public void groupByDemo() {
    Apple chinaApple = new Apple(10, "中国");
    Apple usApple = new Apple(20, "米国");
    Apple koreaApple = new Apple(30, "韩国");
    Apple japanApple = new Apple(40, "日本");

    Map<Quality, List<Apple>> appleQualityMap = Stream.of(chinaApple, usApple, koreaApple, japanApple)
            .collect(Collectors.groupingBy(curApple -> {
                // 质量<=20为优秀,质量>20为一般
                if (curApple.getWeight() <= 20) {
                    return Quality.PERFECT;
                } else {
                    return Quality.NORMAL;
                }
            }));

    System.out.println(JSON.toJSONString(appleQualityMap, true));
}
  • 结果:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "NORMAL": [
    {
      "country": "韩国",
      "weight": 30
    },
    {
      "country": "日本",
      "weight": 40
    }
  ],
  "PERFECT": [
    {
      "country": "中国",
      "weight": 10
    },
    {
      "country": "米国",
      "weight": 20
    }
  ]
}
  • 多级分组
    • 先根据质量进行分组,再根据国家进行分组
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void groupByDemo() {
    Apple chinaApple = new Apple(10, "中国");
    Apple chinaAppleEnhance = new Apple(100, "中国");
    Apple chinaAppleDoubleEnhance = new Apple(1000, "中国");

    Apple usApple = new Apple(20, "米国");

    Apple koreaApple = new Apple(30, "韩国");

    Apple japanApple = new Apple(40, "日本");
    Apple japanAppleEnhance = new Apple(80, "日本");
    Apple japanAppleDoubleEnhance = new Apple(120, "日本");

    Map<Quality, Map<String, List<Apple>>> appleQualityMap = Stream.of(chinaApple, chinaAppleEnhance, chinaAppleDoubleEnhance, usApple, koreaApple, japanApple, japanAppleEnhance, japanAppleDoubleEnhance)
            .collect(Collectors.groupingBy(curApple -> {
                // 质量<=20为优秀,质量>20为一般
                if (curApple.getWeight() <= 20) {
                    return Quality.PERFECT;
                } else {
                    return Quality.NORMAL;
                }
                // 再根据质量进行分组后再根据国家进行分组
            }, Collectors.groupingBy(Apple::getCountry)));


    System.out.println(JSON.toJSONString(appleQualityMap, true));
}
  • 结果
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "NORMAL": {
    "韩国": [
      {
        "country": "韩国",
        "weight": 30
      }
    ],
    "中国": [
      {
        "country": "中国",
        "weight": 100
      },
      {
        "country": "中国",
        "weight": 1000
      }
    ],
    "日本": [
      {
        "country": "日本",
        "weight": 40
      },
      {
        "country": "日本",
        "weight": 80
      },
      {
        "country": "日本",
        "weight": 120
      }
    ]
  },
  "PERFECT": {
    "米国": [
      {
        "country": "米国",
        "weight": 20
      }
    ],
    "中国": [
      {
        "country": "中国",
        "weight": 10
      }
    ]
  }
}
  • 注意:可以无限叠加层N层Map哟。

2. 按子组收集数据(指定用于处理子组数据的函数)

  • 观察源码发现,我们使用最多的接收一个参数的groupingBy()方法其实:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public static <T, K> Collector<T, ?, Map<K, List<T>>>
    groupingBy(Function<? super T, ? extends K> classifier) {
        return groupingBy(classifier, toList());
    }

默认第二个参数是Collectors.toList(),实际上可以替换成我们需要的方法,如计算子组的数量:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void groupByDemo() {
    Apple chinaApple = new Apple(10, "中国");
    Apple chinaAppleEnhance = new Apple(100, "中国");
    Apple chinaAppleDoubleEnhance = new Apple(1000, "中国");

    Apple usApple = new Apple(20, "米国");

    Apple koreaApple = new Apple(30, "韩国");

    Apple japanApple = new Apple(40, "日本");
    Apple japanAppleEnhance = new Apple(80, "日本");
    Apple japanAppleDoubleEnhance = new Apple(120, "日本");

    Map<Quality, Long> qualityLongMap = Stream.of(chinaApple, chinaAppleEnhance, chinaAppleDoubleEnhance, usApple, koreaApple, japanApple, japanAppleEnhance, japanAppleDoubleEnhance)
            .collect(Collectors.groupingBy(curApple -> {
                // 质量<=20为优秀,质量>20为一般
                if (curApple.getWeight() <= 20) {
                    return Quality.PERFECT;
                } else {
                    return Quality.NORMAL;
                }
                // 再根据质量进行分组后再计算每组的元素的个数
            }, Collectors.counting()));
    System.out.println(JSON.toJSONString(qualityLongMap, true));
}
  • 结果:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "PERFECT": 2,
  "NORMAL": 6
}
  • demo2: 先按质量分组,将子组List中的国家名字拼成String打印出来。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void groupByDemo() {
    Apple chinaApple = new Apple(10, "中国");
    Apple usApple = new Apple(20, "米国");
    Apple koreaApple = new Apple(30, "韩国");
    Apple japanApple = new Apple(40, "日本");

    Map<Quality, String> qualityCountryMap = Stream.of(chinaApple, usApple, koreaApple, japanApple)
            .collect(Collectors.groupingBy(curApple -> {
                // 质量<=20为优秀,质量>20为一般
                if (curApple.getWeight() <= 20) {
                    return Quality.PERFECT;
                } else {
                    return Quality.NORMAL;
                }
                // 再将相应分组的国家的名字打印出来
            }, Collectors.mapping(Apple::getCountry, Collectors.joining(","))));
    System.out.println(JSON.toJSONString(qualityCountryMap, true));
}
  • 结果:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "PERFECT": "中国,米国",
  "NORMAL": "韩国,日本"
}
  • demo3: 将子组的结果转换成另外一种格式collectingAndThen()

要求: 先根据apple的weight进行分组,再将每组中weight最大的apple找出来,再返回每组最大的apple的weight,即返回Map<quality, maxWeight>

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void groupByDemo() {
    Apple chinaApple = new Apple(10, "中国");
    Apple usApple = new Apple(20, "米国");
    Apple koreaApple = new Apple(30, "韩国");
    Apple japanApple = new Apple(40, "日本");

    Map<Quality, Integer> qualityCountryMap = Stream.of(chinaApple, usApple, koreaApple, japanApple)
            .collect(Collectors.groupingBy(curApple -> {
                // 质量<=20为优秀,质量>20为一般
                if (curApple.getWeight() <= 20) {
                    return Quality.PERFECT;
                } else {
                    return Quality.NORMAL;
                }
            }, Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingInt(Apple::getWeight)), (optionalApple) -> optionalApple.get().getWeight())));

    System.out.println(JSON.toJSONString(qualityCountryMap, true));
}
  • 结果:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
    "NORMAL":40,
    "PERFECT":20
}

三、分区 partitioningBy()

分区是分组的一种特殊情况,分区返回的Map的keys只有truefalse。其他用法与groupingBy基本一致。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void partitioningByDemo() {
    Apple chinaApple = new Apple(10, "中国");
    Apple usApple = new Apple(20, "米国");
    Apple koreaApple = new Apple(30, "韩国");
    Apple japanApple = new Apple(40, "日本");

    Map<Boolean, String> appleQualityCountryMap = Stream.of(chinaApple, usApple, korea  Apple, japanApple)
            //以质量20为分界线进行分区,将分区之后的apple的原产地的国家返回
            .collect(Collectors.partitioningBy(x -> x.getWeight() > 20, Collectors.mapping(Apple::getCountry, Collectors.joining(","))));
    System.out.println(JSON.toJSONString(appleQualityCountryMap, true));
}
  • 结果:
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "false": "中国,米国",
  "true": "韩国,日本"
}
> 如何自定义Collector?

欢迎在评论区留下你看文章时的思考,及时说出,有助于加深记忆和理解,还能和像你一样也喜欢这个话题的读者相遇~

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

本文分享自 喜欢天文 微信公众号,前往查看

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
linux基础命令介绍十五:推陈出新
本文介绍ip、ss、journalctl和firewall-cmd,它们旨在代替linux中原有的一些命令或服务。
用户5030870
2019/04/11
1.4K0
Linux firewalld防火墙学习总结
Firewalld是一种简单的、有状态的、基于区域(zone-based)的防火墙。策略和区域用于组织防火墙规则。网络在逻辑上被划分为多个区域,它们之间的流量可以通过策略进行管理。
授客
2024/11/21
1900
Linux firewalld防火墙学习总结
CentOS 防火墙常用命令
CentOS中7以下防火墙是 iptables,7是 firewalld,两者不尽相同,一开始以为 firewalld 比 iptables会更麻烦,其实 firewalld 比 iptables 方便多了,这里简单描述下配置。
小唐同学.
2022/02/23
1.6K0
工作总结之linux防火墙配置命令适用centos7、centos8
在CentOS 7中,开启指定区域(zone)中的指定端口8080,或者端口3306、或者指定范围内的端口8080-8088。
Maynor
2022/06/08
5K0
Linux查看开放端口_linux查看对外端口
想通过防火墙打开8080端口登录tomcat却发现提示 /etc/rc.d/init.d/iptable.找不到文件, 最后发现因为于CentOS7不用iptables执行命令了,所以应用firewall相关命令控制防火墙
全栈程序员站长
2022/10/02
93.1K0
Linux查看开放端口_linux查看对外端口
第七章·Firewalld防火墙实战
-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。
DriverZeng
2022/09/26
9480
第七章·Firewalld防火墙实战
firewalld常用命令
firewalld是Linux防火墙管理工具,在CentOS 7及以后版本中默认使用,相对iptables来说,使用更加简单和人性化 安装&启动 sudo yum install firewalld -y sudo systemctl status firewalld sudo systemctl start firewalld sudo systemctl enable firewalld 常用命令 # 查看防火墙规则(只显示/etc/firewalld/zones/public.xml中防火墙策略)
十毛
2022/07/28
3150
CentOS7下Firewall一些基本常用命令
一、介绍  防火墙守护 firewalld 服务引入了一个信任级别的概念来管理与之相关联的连接与接口。它支持 ipv4 与 ipv6,并支持网桥,采用 firewall-cmd (command) 或 firewall-config (gui) 来动态的管理 kernel netfilter 的临时或永久的接口规则,并实时生效而无需重启服务。
拓荒者
2019/03/11
3620
Centos7-Firewall防火墙基础讲解
(1)firewalld简介: 它是Linux上新用的防火墙软件它跟iptables防火墙是差不多的工具但比其更好使用与设置;
全栈工程师修炼指南
2020/10/13
1.9K0
搞它!!!Linux--深入介绍firewalld防火墙管理工具
firewall-cmd是firewalld防火墙自带的字符管理工具,可以用来设置firewalld防火墙的各种规则
不吃小白菜
2020/09/03
2.6K0
搞它!!!Linux--深入介绍firewalld防火墙管理工具
2024全网最为详细的红帽系列【RHCSA-(14)】初级及进阶Linux保姆级别骚操作教程;学不费来砍我[就怕你日后学成黑客了]
(2)在rhel9上,使用NM进行网络配置,NetworkManager现在使用秘钥文件来存储配置信息
盛透侧视攻城狮
2024/10/22
1730
2024全网最为详细的红帽系列【RHCSA-(14)】初级及进阶Linux保姆级别骚操作教程;学不费来砍我[就怕你日后学成黑客了]
CentOS常用指令及心得
注:700模式,意味着该目录除了设置的用户能读写执行此目录以外,拒绝其他任何用户访问。777模式意味着允许任何用户读写执行。600模式,意味着该目录除了设置的用户能读写此目录以外,拒绝其他任何用户访问。
小新笔记坊
2024/12/17
1170
CentOS 7安装完成后初始化
版权声明:本文为木偶人shaon原创文章,转载请注明原文地址,非常感谢。 https://blog.csdn.net/wh211212/article/details/52923673
shaonbean
2019/05/26
2.5K0
openEuler-22.03-LTS-SP3 系统安装
EulerOS 是华为自主研发的服务器操作系统,能够满足客户从传统 IT 基础设施到云计 算服务的需求。EulerOS 对 ARM64 架构提供全栈支持,打造完善的从芯片到应用的一体 化生态系统。EulerOS,以 Linux 稳定系统内核为基础,支持鲲鹏处理器和容器虚拟化技 术,是一个面向企业级的通用服务器架构平台。2021 年 11 月 9 日,在北京举行的 2021 操作系统产业峰会上,华为发布最新的欧拉 系统(openEuler),并将 openEuler 捐赠给中国开放原子开源基金会(OpenAtom Foundation)负责孵化及运营。
Kevin song
2024/03/12
3.1K0
openEuler-22.03-LTS-SP3 系统安装
Linux防火墙firewalld安全设置
防火墙是具有很好的保护作用。入侵者必须首先穿越防火墙的安全防线,才能接触目标计算机。在公司里数据安全是最重要的,要求安全部门进行全公司进行服务器防火墙安全搭建,在原有的基础上进行安全的防火墙设置,大多数生产环境都建议开启,这样才能有效避免安全隐患等问题;本文文字偏多,但是建议大家还是花个十多分钟好好看一下防火墙的原理,这样便于后期问题排查,最后一小节也会有常用命令操作。
没有故事的陈师傅
2019/11/22
4.1K0
Linux关闭防火墙命令
Centos7默认安装了firewalld,如果没有安装的话,可以使用 ***yum install firewalld firewalld-config***进行安装。
jwangkun
2021/12/23
67K0
Linux关闭防火墙命令
CentOS 7上防火墙 firewalld 的常用命令
在 CentOs 7 中 firewalld,iptables,ebtables 这三种防火墙是共存的。 但是默认情况下使用 firewalld 来管理 netfilter 子系统。
求和小熊猫
2020/11/25
7.2K0
Linux firewall-cmd命令
firewall-cmd 是 firewalld的字符界面管理工具,firewalld是centos7的一大特性,最大的好处有两个:支持动态更新,不用重启服务;第二个就是加入了防火墙的“zone”概念。
IT工作者
2022/03/23
1.9K0
运维 | 在企业环境中快速安装配置 Rocky Linux 服务器操作系统
描述: 在 2020 年 12 月所宣布的,CentOS 计划已将重点从 CentOS Linux 转移到 CentOS Stream,这是一个介于Fedora和RHEL之间的发行版,旨在作为RHEL的上游(即测试、预发布版本)。并且 CentOS Stream 8 也将于 2024 年结束迭代更新补丁, 鉴于被 Redhat 收购的 CentOS 即将停止更新维护了,然而在企业中还有大量的 CentOS 的服务器操作系统,不得不考虑其替代产品,此时 原 CentOS 创始人之一的 Gregory Kurtzer 为纪念其创始成员 Rocky McGaugh,创建了 Rocky Linux 与 RHEL 百分之百兼容,目的是用于替代 CentOS Stream 发行版本。
全栈工程师修炼指南
2024/03/25
4.6K0
运维 | 在企业环境中快速安装配置 Rocky Linux 服务器操作系统
Could not connect to ‘ip‘ (port 22): Connection failed. liunx服务器ping不通[通俗易懂]
Lsof命令详解 https://blog.csdn.net/Aquester/article/details/23339651
全栈程序员站长
2022/09/23
1.8K0
相关推荐
linux基础命令介绍十五:推陈出新
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验