Java8--Stream的各种用法(二):collect、Collectors

news2024/11/27 0:33:45

Collectors中的方法: 

 

 其中我们常用的是前三个:将流中的元素放到集合中、分组、toMap。 下面我们逐个介绍这些方法的使用.

基础类: Student

public class Student {
    private Integer id;

    private String name;

    private String className;

    private Double score;
 
    private Long timeStamp;
}

1、将流中的元素放到集合中: 

1.1 toCollection(Supplier<C> collectionFactory) : 

    public static <T, C extends Collection<T>> Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {
        return new CollectorImpl<>(collectionFactory, Collection<T>::add,
                                   (r1, r2) -> { r1.addAll(r2); return r1; },
                                   CH_ID);
    }

示例: 

List<Student> studentList = new ArrayList<>();

LinkedList<Integer> collect = studentList.stream().map(Student::getId).collect(Collectors.toCollection(LinkedList::new));
        

1.2  toList() 、toSet() :

直接上示例: 

List<Integer> list = studentList.stream().map(Student::getId).collect(Collectors.toList());

Set<String> nameSet = studentList.stream().map(Student::getName).collect(Collectors.toSet());

2、分组

2.1 groupingBy 它有三个重载方法: 

    public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingBy(Function classifier) {
        return groupingBy(classifier, toList());
    }

    public static <T, K, A, D> Collector<T, ?, Map<K, D>> groupingBy(Function classifier, Collector downstream) {
        return groupingBy(classifier, HashMap::new, downstream);
    }

    public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M> groupingBy(Function classifier, Supplier mapFactory, Collector downstream) {
        ......
    }

第一个方法只需一个分组参数classifier,内部自动将结果保存到一个map中,每个map的键为 ‘?’ 类型(即classifier的结果类型),值为一个list,这个list中保存在属于这个组的元素。 但是它实际是调用了第二个方法-- Collector 默认为list。而第二个方法实际是调用第三个方法,默认Map的生成方式为HashMap。 第三个方法才是真实完整的分组逻辑处理。

 示例: 

Stream<Student> stream = studentList.stream();

Map<Double, List<Student>> m1 = stream.collect(Collectors.groupingBy(Student::getScore));

Map<Double, Set<Student>> m2 = stream.collect(Collectors.groupingBy(Student::getScore, Collectors.toSet()));

Map<Double, Set<Student>> m3 = stream.collect(Collectors.groupingBy(Student::getScore,TreeMap::new, Collectors.toSet()));
        

2.2  groupingByConcurrent  

返回一个并发Collector收集器对T类型的输入元素执行"group by"操作, 也有三个重载的方法, 其使用与groupingBy 基本相同。 

2.3 partitioningBy

该方法将流中的元素按照给定的校验规则的结果分为两个部分,放到一个map中返回,map的键是Boolean类型,值为元素的集合

两个重载的方法: 

    public static <T> Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {
        return partitioningBy(predicate, toList());
    }

    public static <T, D, A> Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
                                                    Collector<? super T, A, D> downstream) {
        ......
    }

从上面的重载方法中可以看出,partitioningBy 与 groupingBy 类似, 只不过partitioningBy 生成的map的key的类型限制只能是Boolean类型。

示例: 

Stream<Student> stream = studentList.stream();

Map<Boolean, List<Student>> m4 = stream.collect(Collectors.partitioningBy(stu -> stu.getScore() > 60));

Map<Boolean, Set<Student>> m5 = stream.collect(Collectors.partitioningBy(stu -> stu.getScore() > 60, Collectors.toSet()));

3、toMap

toMap方法是根据给定的键生成器和值生成器生成的键和值保存到一个map中返回,键和值的生成都依赖于元素,可以指定出现重复键时的处理方案和保存结果的map。

toMap也有三个重载的方法: 

public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function keyMapper,Function valueMapper) {
    return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
}

public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(Function keyMapper,Function valueMapper,BinaryOperator mergeFunction) {
    return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
}

public static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> toMap(Function keyMapper,Function valueMapper,BinaryOperator mergeFunction,Supplier mapSupplier){
    ......
}

三个重载的方法,最终都是调用第三个方法来实现, 第一个方法中默认指定了key重复的处理方式和map的生成方式; 而第二个方法默认指定了map的生成方式,用户可以自定义key重复的处理方式。

示例: 

Map<Integer, Student> map1 = stream.collect(Collectors.toMap(Student::getId, v->v));
Map<Integer, String> map2 = stream.collect(Collectors.toMap(Student::getId, Student::getName, (a, b)->a));
Map<Integer, String> map3 = stream.collect(Collectors.toMap(Student::getId, Student::getName, (a, b)->a, HashMap::new));
toConcurrentMap的使用与toMap基本一致, 只不过toConcurrentMap 用于处理并发请求,它生成的map是 ConcurrentHashMap

4、元素拼接joining

三个重载方法: 

  1. joining() : 没有分隔符和前后缀,直接拼接
  2. joining(CharSequence delimiter) : 指定元素间的分隔符
  3. joining(CharSequence delimiter,CharSequence prefix, CharSequence suffix):  指定分隔符和整个字符串的前后缀。
Stream<String> stream = Stream.of("1", "2", "3", "4", "5", "6");
String s = stream.collect(Collectors.joining(",", "prefix", "suffix"));
        

joining 之前,Stream 必须是Stream<String> 类型

5、类型转换

mapping:这个映射是首先对流中的每个元素进行映射,即类型转换,然后再将新元素以给定的Collector进行归纳。 类似与Stream的map方法。

collectingAndThen:在归纳动作结束之后,对归纳的结果进行再处理。

Stream<Student> stream = studentList.stream();

List<Integer> idList = stream.collect(Collectors.mapping(Student::getId, Collectors.toList()));

Integer size = stream.collect(Collectors.collectingAndThen(Collectors.mapping(Student::getId, Collectors.toList()), o -> o.size()));

6、聚合

  1. counting: 同 stream.count()
  2. minBy:  同stream.min()
  3. maxBy: 同stream.max()
  4. summingInt: 
  5. summingLong:
  6. summingDouble:
  7. averagingInt:
  8. averagingLong:
  9. averagingDouble:
        Long count = stream.collect(Collectors.counting());
        stream.count();
        stream.collect(Collectors.minBy((a,b)-> a.getId() - b.getId()));
        stream.min(Comparator.comparingInt(Student::getId));
        stream.collect(Collectors.summarizingInt(Student::getId));
        stream.collect(Collectors.summarizingLong(Student::getTimeStamp));
        stream.collect(Collectors.averagingDouble(Student::getScore));

7、reducing

reducing方法有三个重载方法,其实是和Stream里的三个reduce方法对应的,二者是可以替换使用的,作用完全一致,也是对流中的元素做统计归纳作用。

public static <T> Collector<T, ?, Optional<T>> reducing(BinaryOperator<T> op) {
    ......
}

public static <T> Collector<T, ?, T> reducing(T identity, BinaryOperator<T> op) {
    ......
}

public static <T, U> Collector<T, ?, U> reducing(U identity,Function mapper, BinaryOperator<U> op) {
    ......
}

示例:

List<String> list2 = Arrays.asList("123","456","789","qaz","wsx","edc");

Optional<Integer> optional = list2.stream().map(String::length).collect(Collectors.reducing(Integer::sum));

Integer sum1 = list2.stream().map(String::length).collect(Collectors.reducing(0, Integer::sum));

Integer sum2 = list2.stream().limit(4).collect(Collectors.reducing(0, String::length, Integer::sum));

扩展: 

实际运用中,可能会用到比较复杂的 groupingBy、mapping、toMap 嵌套、组合使用,进行多级分组处理数据。如: 

Stream<Student> stream = studentList.stream();
// 根据score分组,并提取ID作为集合元素
Map<Double, List<Integer>> map1 = stream.collect(Collectors.groupingBy(Student::getScore, Collectors.mapping(Student::getId, Collectors.toList())));
// 根据score分组, 并将ID和name组成map作为元素
Map<Double, Map<Integer, String>> map2 = stream.collect(Collectors.groupingBy(Student::getScore, Collectors.toMap(Student::getId, Student::getName)));
// 先根据score分组,再根据name进行二次分组
Map<Double, Map<String, List<Student>>> map3 = stream.collect(Collectors.groupingBy(Student::getScore, Collectors.groupingBy(Student::getName)));

当然也可以根据我们想要的条件,设置分组的组合条件,只需要替换 Student::getScore ,换成我们想要的条件即可, 如: 

    Map<String, List<Integer>> map3 = stream.collect(Collectors.groupingBy(stu -> {
                                                                                    if (stu.getScore() > 60) {
                                                                                        return "PASS";
                                                                                    } else {
                                                                                        return "FAIL";
                                                                                    }
                                                                                }, Collectors.mapping(Student::getId, Collectors.toList())));

按照这种思路,我们可以随意处理stream中的元素成我们想要的结果数据。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux21 --- 计算机网络基础概论(网络基本概念、网络分层模型、网络应用程序通信流程)

一、网络基本概念 1、网络 网络是由若干结点和连接这些结点的链路组成&#xff0c;网络中的结点可以是计算机&#xff0c;交换机、 路由器等设备。 网络设备有&#xff1a;交换机、路由器、集线器 传输介质有&#xff1a;双绞线、同轴电缆、光纤 下图是一个简单的网络示意图…

应急启动电源+充气一体式方案设计

汽车应急启动电源是为驾车出行的爱车人士和商务人士所开发出来的一款多功能便携式移动电源。它的特色功能是用于汽车亏电或者其他原因无法启动汽车的时候能启动汽车。同时将充气泵与应急电源、户外照明等功能结合起来&#xff0c;是户外出行必备的产品之一。 汽车应急启动电源应…

springboot源码编译报错Unable to start the daemon process

官方网址&#xff1a;GitHub - spring-projects/spring-boot: Spring Boot springboot版本&#xff1a; 报错截图&#xff1a; 报错代码&#xff1a; Unable to start the daemon process. This problem might be caused by incorrect configuration of the daemon. For examp…

jsp196ssm毕业设计选题管理系统hsg4361B6

本系统选用Windows作为服务器端的操作系统&#xff0c;开发语言选用Java&#xff0c;数据库选用Mysql&#xff0c;使用mybatis数据库连接技术&#xff0c;使用Myeclipse作为系统应用程序的开发工具&#xff0c;Web服务器选用Tomcat版本。 下面分别简单阐述一下这几个功能模块需…

pytest配置文件合集(一)-----------conftest.py应用

配置文件&#xff1a; 配置文件一般存在项目的根目录下&#xff0c;官方文档介绍了四种配置文件&#xff0c;每种文件有各自的用处。 pytest.ini&#xff1a;主配置文件&#xff0c;最常用&#xff0c;优先匹配配置项 tox.ini &#xff1a;可以理解为pytest.ini的另一种写法&…

接口测试方法论——WebSocket一点通

WebSocket是HTML5提供的一种能在单个TCP连接上进行全双工通信的协议。前面介绍过&#xff0c;HTTP是一种无状态、无连接、单向的应用层协议。 HTTP采用了请求/响应模型&#xff1a;通信请求只能由客户端发起&#xff0c;服务器负责对请求做出应答处理。但这会出现一个很严重的…

【Java集合】List接口常用方法及实现子类

文章目录List接口> List 接口的常用方法> List的三种遍历方式> List 排序练习※ ArrayList 使用注意事项※ ArrayList 底层结构※ Vector 底层结构※ LinkedList 底层结构 &#xff08;双向链表和增删改查案例&#xff09;> ArrayList 和 LinkedList 比较List接口 …

字节跳动岗位薪酬体系曝光,看完感叹:不服不行

曾经的互联网是PC的时代&#xff0c;随着智能手机的普及&#xff0c;移动互联网开始飞速崛起。而字节跳动抓住了这波机遇&#xff0c;2015年&#xff0c;字节跳动全面加码短视频&#xff0c;从那以后&#xff0c;抖音成为了字节跳动用户、收入和估值的最大增长引擎。 自从字节…

postgresql源码学习(51)—— 提交日志CLOG 提交日志CLOG 原理 用途 管理函数

一、 CLOG是什么 CLOG&#xff08;commit log&#xff09;记录事务的最终状态。 物理上&#xff0c;是$PGDATA/pg_xact目录下的一些文件逻辑上&#xff0c;是一个数组&#xff0c;下标为事务id&#xff0c;值为事务最终状态1. 事务最终状态 clog.h中定义了4种事务状态 /** …

Android开发:Fragment中优雅使用ViewBinding【Java】

目录 前言 官网示例 封装 前言 ViewBinding可以帮助我们减少代码中的大部分findViewById&#xff0c;官网中提到了它的优点和缺点&#xff1a; Null 安全&#xff1a;由于视图绑定会创建对视图的直接引用&#xff0c;因此不存在因视图 ID 无效而引发 Null 指针异常的风险…

Kotlin小知识之高阶函数

文章目录高阶函数定义高阶函数函数类型高阶函数示例内联函数内联函数的作用内联函数的用法noinline与crossinline高阶函数 定义高阶函数 高阶函数和Lambda的关系是密不可分的.像接受Lambda参数的函数就可以称为具有函数式编程风格的API了当我们想要定义自己的函数式API那就得…

使用 Learner Lab - 使用 AWS Lambda 将图片写入 S3

使用 Learner Lab - 使用 AWS Lambda 将图片写入 S3 AWS Academy Learner Lab 是提供一个帐号让学生可以自行使用 AWS 的服务&#xff0c;让学生可以在 100 USD的金额下&#xff0c;自行练习所要使用的 AWS 服务&#xff0c;以下使用 AWS Lambda 将图片写入 S3。 如何进入 Le…

Git源码(Linus 2005 年提交的最初版本)阅读笔记

Linus 发疯文学欣赏 Git 是 Linux 之父 Linus Torvalds 于2005年开发的用于帮助管理 Linux 内核开发的开源版本控制软件。 美好的一天从阅读 Linus 的发疯文学开始。 (1) Linus 教你学习 Git (2) Linus 评价 CVS (Concurrent Version System) (3) 独一无二的 Linus 调侃结束&a…

手把手教你写一个生成yapi接口代码Chrome 扩展插件

前言 公司想开发个公众号&#xff0c;想在公众号里做业务&#xff0c;也不是做小程序&#xff0c;但是以后也可能做小程序。emm&#xff0c;就是这么随意。所以就找个到了uniapp&#xff0c;说是可以开发一套代码&#xff0c;多平台运行。开发语法还是vue&#xff0c;感觉也没…

RabbitMQ消息队列——快速入门

目录 1、MQ介绍 1.1、什么是MQ&#xff1f; 1.2、MQ的能够解决的问题 1.2.1、削峰填谷 1.2.3、异步处理 1.3、MQ的选择 1.3.1、Kafka 1.3.2、ActiveMQ 1.3.3、RocketMQ 1.3.4、RabbitMQ 2、RabbitMQ的介绍 2.1、RabbitMQ的概述 2.2、AMQP 2.3、JMS 2.4、RabbitMQ…

关系抽取:传统:UniRel: Unified Representation and Interaction for Joint Relational

针对传统下的三元组抽取提出的一种方法&#xff0c;在NYT和webNLG数据集上&#xff0c;再次刷新榜单。 本来对这个结果不是很确定&#xff0c;但作者公布了源码&#xff0c;we can reformulate it . 很少在看到这种文章了吧。 Core idea 换了一种解释思路。 从entity-entity的…

ARM汇编之乘法指令

ARM汇编之乘法指令前言 首先&#xff0c;请问大家几个小小问题&#xff0c;你清楚&#xff1a; 乘法指令有哪些种类呢&#xff1f;ARM乘法指令具体的使用场景又有哪些&#xff1f; 今天&#xff0c;我们来一起探索并回答这些问题。为了便于大家理解&#xff0c;以下是本文的…

精准诊断,精确治疗,智芯传感ZXPA侵入式压力传感器为心血管疾病患者带来福音

近日&#xff0c;据联合国《世界人口展望2022》报告显示&#xff0c;地球人口已正式步入“80亿时代”&#xff01;人口数量增加&#xff0c;从一个侧面反映了人类文明的进步。此外&#xff0c;随着人类预期寿命增加&#xff0c;加上生育率下降&#xff0c;将加剧全球人口老龄化…

基于模型的聚类和R语言中的高斯混合模型

介绍 四种最常见的聚类方法模型是层次聚类&#xff0c;k均值聚类&#xff0c;基于模型的聚类和基于密度的聚类 . 最近我们被客户要求撰写关于聚类的研究报告&#xff0c;包括一些图形和统计输出。 可以基于两个主要目标评估良好的聚类算法&#xff1a; 高组内相似性低组间相…

小程序中的自定义组件以及组件通信、数据共享、插槽、behaviors

一、创建组件和使用自定义组件 1.创建组件 ①在项目的根目录中&#xff0c;鼠标右键&#xff0c;创建components -> 文件夹 ②在新建的components -> 文件夹上,鼠标右键&#xff0c;点击“新建Component ③键入组件的名称之后回车&#xff0c;会自动生成组件对应的4个…