深入理解Java中的Collectors(Stream流)

在这里插入图片描述

引言

在 Java 的 Stream API 中,Collectors 是一个非常强大的工具类,它提供了许多静态方法,用于将 Stream 的元素收集到集合、字符串或其他类型的结果中。使用 Collectors,我们可以轻松地进行数据聚合和转换操作。

文章目录

  • 引言
  • 什么是 Collectors?
  • 常用 Collectors 方法详解
    • toList()
    • toSet()
    • toMap()
    • joining()
    • groupingBy()
    • partitioningBy()
    • summarizingInt()
    • reducing()
    • counting()
  • 高级用法
    • 嵌套收集器
    • 自定义收集器
  • 注意事项

什么是 Collectors?

Collectors 类是 Java 中的一个实用工具类,包含了一系列静态方法,这些方法用于创建各种常见的集合操作。它们用于将流中的元素累积到某些结果中,例如 List、Set、Map 等,还可以进行各种统计操作,如求和、平均、最小值、最大值等。

Collectors 类位于 java.util.stream 包中,通常与 Stream 的 collect() 方法一起使用。它的设计遵循了函数式编程的原则,使得数据处理变得更加简洁和高效。

常用 Collectors 方法详解

下面将详细介绍一些常用的 Collectors 方法,并通过通俗易懂的示例来展示它们的使用。

toList()

toList() 方法是最简单的收集器,它将流中的元素收集到一个 List 中。这是一个无参数方法,返回一个新的 List。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class CollectorsToListExample {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "cherry");
        List<String> result = fruits.stream().collect(Collectors.toList());
        System.out.println(result); // 输出 [apple, banana, cherry]
    }
}

在这个例子中,将一个包含水果名称的 List 转换为一个 Stream,并使用 Collectors.toList() 方法将其收集回一个 List。

toSet()

toSet() 方法将流中的元素收集到一个 Set 中,自动去除重复项。这也是一个无参数方法,返回一个新的 Set。

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class CollectorsToSetExample {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "cherry", "apple");
        Set<String> result = fruits.stream().collect(Collectors.toSet());
        System.out.println(result); // 输出 [banana, cherry, apple]
    }
}

在这个例子中,有一个包含重复元素的 List,通过 Collectors.toSet() 方法,我们将其收集到一个 Set 中,从而去除了重复元素。

toMap()

toMap() 方法需要两个函数:一个用于生成键,另一个用于生成值。它将流中的元素收集到一个 Map 中。

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class CollectorsToMapExample {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "cherry");
        Map<String, Integer> result = fruits.stream().collect(Collectors.toMap(
            fruit -> fruit, // 键映射函数
            String::length  // 值映射函数
        ));
        System.out.println(result); // 输出 {banana=6, cherry=6, apple=5}
    }
}

在这个例子中,将水果名称作为键,水果名称的长度作为值,收集到一个 Map 中。

joining()

joining() 方法可以将流中的字符串元素连接成一个单一的字符串。它可以有三个参数:分隔符、前缀和后缀。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class CollectorsJoiningExample {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "cherry");
        String result = fruits.stream().collect(Collectors.joining(", ", "[", "]"));
        System.out.println(result); // 输出 [apple, banana, cherry]
    }
}

在这个例子中,使用 Collectors.joining() 方法将水果名称连接成一个字符串,并指定了逗号作为分隔符,方括号作为前缀和后缀。

groupingBy()

groupingBy() 方法根据提供的函数对流中的元素进行分组,返回一个 Map,其中键是分组函数的结果,值是符合该分组的元素列表。

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class CollectorsGroupingByExample {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "cherry", "apricot");
        Map<Character, List<String>> result = fruits.stream().collect(Collectors.groupingBy(fruit -> fruit.charAt(0)));
        System.out.println(result); // 输出 {a=[apple, apricot], b=[banana], c=[cherry]}
    }
}

在这个例子中,按水果名称的首字母对水果进行分组。

partitioningBy()

partitioningBy() 方法根据提供的谓词对流中的元素进行分区,返回一个 Map,其中键是布尔值,值是符合或不符合谓词的元素列表。

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class CollectorsPartitioningByExample {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "cherry", "apricot");
        Map<Boolean, List<String>> result = fruits.stream().collect(Collectors.partitioningBy(fruit -> fruit.startsWith("a")));
        System.out.println(result); // 输出 {false=[banana, cherry], true=[apple, apricot]}
    }
}

在这个例子中,根据水果名称是否以字母 ‘a’ 开头将水果分为两个部分。

summarizingInt()

summarizingInt() 方法接收一个将对象转换为 int 的函数,并返回一个 IntSummaryStatistics 对象,其中包含元素的数量、总和、最小值、平均值和最大值。

import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.stream.Collectors;

public class CollectorsSummarizingIntExample {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "cherry");
        IntSummaryStatistics stats = fruits.stream().collect(Collectors.summarizingInt(String::length));
        System.out.println(stats); // 输出 IntSummaryStatistics{count=3, sum=17, min=5, average=5.666667, max=6}
    }
}

在这个例子中,统计了水果名称的长度信息。

reducing()

reducing() 方法是一个通用的归约操作,它可以将流中的元素归约成一个值。它需要三个参数:初始值、累加器和组合器。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class CollectorsReducingExample {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "cherry");
        int totalLength = fruits.stream().collect(Collectors.reducing(0, String::length, Integer::sum));
        System.out.println(totalLength); // 输出 17
    }
}

在这个例子中,将水果名称的长度进行归约操作,计算它们的总长度。

counting()

counting() 是一个简单的归约操作,用于计算流中元素的数量。

long count = list.stream().collect(Collectors.counting());

高级用法

除了上述基本用法外,Collectors 还提供了一些高级用法,可以实现更复杂的数据处理需求。

嵌套收集器

Collectors 允许嵌套使用,这意味着我们可以在一个收集操作中组合多个收集器。例如,我们可以先按照某个条件分组,然后对每个组应用另一个收集器。

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class NestedCollectorsExample {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");
        Map<Integer, Long> lengthCounts = fruits.stream()
            .collect(Collectors.groupingBy(
                String::length,
                Collectors.counting()
            ));
        System.out.println(lengthCounts); // 输出 {4=1, 5=2, 6=1, 10=1}
    }
}

在这个例子中,我们首先按照字符串长度分组,然后对每个组计数。

自定义收集器

虽然 Collectors 类提供了许多预定义的收集器,但有时我们可能需要创建自定义的收集器来满足特定需求。我们可以通过实现 Collector 接口来创建自定义收集器。


Collector<T, A, R> 是一个泛型接口,其中:

  • T 是要收集的元素类型
  • A 是累加器的类型(中间结果)
  • R 是最终结果的类型

这个 Collector 接口定义了五个方法:

  1. supplier(): 提供一个初始的空累加器
  2. accumulator(): 定义如何将新元素添加到累加器中
  3. combiner(): 定义如何合并两个累加器
  4. finisher(): 定义如何从累加器得到最终结果
  5. characteristics(): 定义收集器的特征

收集器的特征就像是收集器的"说明书"。它告诉Java这个收集器有什么特别之处,可以怎么用。比如,“CONCURRENT"特征就像说"多人可以同时使用”,这样Java就知道可以让多个线程一起工作。“UNORDERED"特征就像说"不用排队”,Java就知道不需要保持元素的顺序。“IDENTITY_FINISH"特征就像说"装好就直接用”,Java就知道不用再额外处理结果。有了这些"说明",Java就能更聪明地使用收集器,让程序运行得更快更好。这就像你在使用一个工具时,了解了它的特点,就能更好地发挥它的作用。

import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;

public class CustomCollectorExample {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");
        String result = fruits.stream().collect(new CustomJoiningCollector());
        System.out.println(result); // 输出 "APPLE, BANANA, CHERRY, DATE"
    }

    static class CustomJoiningCollector implements Collector<String, StringBuilder, String> {
        @Override
        public Supplier<StringBuilder> supplier() {
            return StringBuilder::new;
        }

        @Override
        public BiConsumer<StringBuilder, String> accumulator() {
            return (sb, s) -> {
                if (sb.length() > 0) sb.append(", ");
                sb.append(s.toUpperCase());
            };
        }

        @Override
        public BinaryOperator<StringBuilder> combiner() {
            return StringBuilder::append;
        }

        @Override
        public Function<StringBuilder, String> finisher() {
            return StringBuilder::toString;
        }

        @Override
        public Set<Characteristics> characteristics() {
            return Collections.emptySet();
        }
    }
}

这个自定义收集器将字符串转换为大写并用逗号分隔。

注意事项

  1. 在使用 Collectors 的 toMap() 方法时,如果流中存在相同的键,则默认会抛出 IllegalStateException。可以通过提供合并函数来处理键冲突。
  2. 当使用并行流时,需要注意线程安全问题。虽然 Collectors 的大多数方法在并行流中都是安全的,但在收集到特定的集合时,可能需要使用线程安全的集合或者在收集操作后进行同步。
  3. 对于大型数据集,使用 Collectors 的某些方法(如 toList、toSet)可能不如直接使用特定类型的集合(如 ArrayList、HashSet)高效。此外,groupingBy 和 partitioningBy 在处理大型数据集时可能会消耗较多内存。
  4. 在需要去重时选择 toSet() 而不是 toList()。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/744573.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小区业主管理系统

摘 要 随着城市化进程的加速和人口的不断增加&#xff0c;小区的数量也在不断增加。小区作为城市居民居住的主要场所&#xff0c;其管理工作也变得越来越重要。传统的小区业主管理方式存在诸多问题&#xff0c;如信息传递不畅、业务处理效率低下等。因此&#xff0c;开发一个高…

Spring底层原理之FactoryBean Bean工厂 单例对象 多例对象

FactoryBean 在 Spring Framework 中&#xff0c;FactoryBean 是一个用于创建其他 Bean 实例的特殊工厂 Bean。它允许开发者自定义 Bean 的创建逻辑&#xff0c;从而更加灵活地管理和配置 Bean 的实例化过程。 FactoryBean 接口 FactoryBean 接口是 Spring 框架中的一个重要…

启动VMWare虚拟机报错

1. 无法打开内核设备“\\.\VMCIDev\VMX”: 操作成功完成。是否在安装 VMware Workstation 后重新引导? 模块“DevicePowerOn”启动失败。 未能启动虚拟机。 解决办法: 解决办法: 将 Ubuntu 64 位.vmx 找到vmci0.present"TRUE"这行改成 vmci0.present "FAL…

【AI编译器】triton学习:矩阵乘优化

Matrix Multiplication 主要内容&#xff1a; 块级矩阵乘法 多维指针算术 重新编排程序以提升L2缓存命 自动性能调整 Motivations 矩阵乘法是当今高性能计算系统的一个关键组件&#xff0c;在大多数情况下被用于构建硬件。由于该操作特别复杂&#xff0c;因此通常由软件提…

fail2ban自动屏蔽之jumpserver

fail2ban是一款实用软件&#xff0c;可以监视你的系统日志&#xff0c;然后匹配日志的错误信息&#xff08;正则式匹配&#xff09;执行相应的屏蔽动作。 jumpserver是一款开源堡垒机&#xff0c;其拥有一定的防护登录&#xff0c;也可以做登录限制&#xff0c;但是相对于防火…

湖南(用户画像)源点调研 适用于新产品开发的市场调研方法

湖南&#xff08;上市验证调研&#xff09;源点咨询认为&#xff1a;其实市场与用户研究的方法不管都什么花哨的名头&#xff0c;本质上只有两种&#xff1a;定量与定性。而对于新产品的开发最重要的就是掌握好定性的研究方法。 问&#xff1a;对于新产品开发我们面对的是什么…

js如何使得四舍五入的百分比之和为100%

在JavaScript中&#xff0c;如果你想要确保一组四舍五入后的百分比之和严格等于100%&#xff0c;那么你不能直接对每个百分比进行四舍五入&#xff0c;因为四舍五入会引入误差。但是&#xff0c;你可以采用一种策略&#xff0c;即先对所有的百分比进行常规的四舍五入&#xff0…

SNEC天合储能秀:全球首发多元场景一站式工商业储能融合解决方案

6月13日-15日&#xff0c;SNEC2024光伏与智慧能源展在上海隆重举行&#xff0c;来自全球95个国家和地区3000家国内外展商齐聚展会&#xff0c;5000行业专家共话产业发展。致力于成为全球光储智慧能源解决方案的领导者&#xff0c;天合光能&#xff08;展位号&#xff1a;7.2H-E…

线性和二次判别分析

线性判别分析 线性判别分析&#xff08;Linear Discriminant Analysis&#xff0c;LDA&#xff09;亦称 Fisher 判别分析。其基本思想是&#xff1a;将训练样本投影到低维超平面上&#xff0c;使得同类的样例尽可能近&#xff0c;不同类的样例尽可能远。在对新样本进行分类时&…

测试行业,你的未来路在何方?失业之外,暗藏的这个危机更可怕!

目前测试行业现状 近期飞书的大规模裁员&#xff0c;无疑为2024年伊始蒙上了一层阴影。再加上“共享员工”模式的兴起&#xff0c;对于身处互联网行业的从业者来说&#xff0c;无疑是雪上加霜。 此外&#xff0c;延续了2023年的情况&#xff0c;在求职平台如BOSS直聘上&#…

基于Java的宠物领养管理系统【附源码】

摘 要 近些年来&#xff0c;随着科技的飞速发展&#xff0c;互联网的普及逐渐延伸到各行各业中&#xff0c;给人们生活带来了十分的便利&#xff0c;宠物管理系统利用计算机网络实现信息化管理&#xff0c;使整个宠物领养的发展和服务水平有显著提升。 本文拟采用IDEA开发工具…

《编译原理》阅读笔记:p19-p24

《编译原理》学习第 4 天&#xff0c;p19-p24总结&#xff0c;总计 5 页。 一、技术总结 1.grouping of phases 这里谈到分组(group)&#xff0c;那么就会有一个疑问&#xff0c;分组的依据是什么&#xff1f;即根据什么来分组。 (1) front end & back end 编译器包含…

第三十一篇——大数据1:从四个特征把握大数据的本质

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 大数据的特征&#xff0c;如果我们没有一个清晰的边界以及明确的定位&…

如何找到合适的Python第三方库?

找合适的Python库其实很简单&#xff0c;按照以下三步法&#xff0c;你能找到90%的Python库。 1、百度谷歌搜索 明确自己的需求&#xff0c;用Python来干什么&#xff0c;力求简短明了。比如定位“数据分析”&#xff0c;然后去搜索关键词【Python数据分析第三方库】&#xf…

第二证券:港交所上市24周年 市值增长38倍

香港交易及结算所有限公司&#xff08;下称香港交易所&#xff09;于近来举办庆典活动&#xff0c;庆祝上市24周年。 据介绍&#xff0c;自2000年起&#xff0c;香港交易所逐步发展成为全球领先的商场营运机构&#xff0c;也成为连接中国内地与国际商场的主要桥梁。到2024年6月…

解决IMX6ULL GPIO扩展板PWM7/8中的pwm0/period后卡死问题

前言 本篇文章主要是记录解决百问网论坛上面设置 IMX6ULL GPIO扩展板PWM7/8中的pwm0/period后卡死问题&#xff0c;如下图&#xff1a; 一、查看原理图&#xff0c;找出对应引脚 在这里我们如何确定哪个扩展口中的引脚输出PWM波呢&#xff1f;我们可以通过查看原理图。 查看…

鸿蒙开发系统基础能力:【@ohos.inputMethodEngine (输入法服务)】

输入法服务 说明&#xff1a; 本模块首批接口从API version 8开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import inputMethodEngine from ohos.inputMethodEngine;inputMethodEngine 常量值。 系统能力&#xff1a;以下各项对应…

手慢无!限量奶茶免费领,千元大奖组队赢!

&#x1f680; AI 卡片大作战全新启动&#xff01;&#xff01;&#x1f552; 限时两周&#xff0c;组队狂欢&#xff01;&#x1f46b; 邀请好友&#xff0c;解锁免费奶茶福利&#xff01;&#x1f4b0; 学习卡片&#xff0c;赢取 1888 超级现金大奖心动不如行动&#xff0c;快…

试题与研究杂志试题与研究杂志社试题与研究编辑部2024年第16期目录

教海纵横 互动式教学模式在初中道德与法治课的应用探究 陈文海; 1-3 基于跨学科项目式学习的地理研学旅行课程设计——以“佛山梁园”为例 周红艳; 4-6 育人导向下道德与法治教学与社会实践活动的融合探索 李鹤群; 7-9 合作学习模式下的初中数学教学策略探究 张…

Mongo Express 未授权访问漏洞

【产品&&漏洞简述】 Mongo Express 是一个基于 Node.js 和 express 的开源的 MongoDB Web管理界面。Mongo Express存在未授权访问漏洞&#xff0c;攻击者可通过该漏洞获取用户信息或修改系统数据。 【资产测绘Query】 title"Home - Mongo Express" 【产品界…