Java8中比较器和收集器的常用示例-排序、流转集合、分组、分区、查找最大最小值
admin
2024-05-07 02:04:02
0

场景

Java8新特性-Stream对集合进行操作的常用API:

Java8新特性-Stream对集合进行操作的常用API_霸道流氓气质的博客-CSDN博客_streamapi对集合修改

前面讲Stream的常用api。下面讲比较器和收集器的常用示例。

Java 8 为 java.util.Comparator 接口新增了多种静态和默认方法,使排序操作变得更为简单。

现在,只需通过一系列库调用,就能根据一个属性对 POJO 集合进行排序。

Java 8 还引入了一个新的工具类java.util.stream.Collectors,它提供将流转换回各类集合所需的静态方法。

此外,收集器也可以在“下游”使用,利用它们对分组(grouping)或分区(partitioning)操作进行后期处理

注:

博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主

实现

利用比较器实现排序

根据字典顺序(自然顺序)对字符串集合排序

        List sampleStrings = Arrays.asList("a","d","eee","fff","b");List collect = sampleStrings.stream().sorted().collect(Collectors.toList());System.out.println(collect);//[a, b, d, eee, fff]

根据长度对字符串集合进行排序

        List sampleStrings1 = Arrays.asList("a","dd","eee","fffg","bgggg");List collect1 = sampleStrings1.stream().sorted(Comparator.comparingInt(String::length)).collect(Collectors.toList());System.out.println(collect1);//[a, dd, eee, fffg, bgggg]

根据长度和字母顺序对字符串集合进行排序,如果长度相同则按照字母顺序排序

        List stringList = Arrays.asList("a","ddd","bb","cc");List collect2 = stringList.stream().sorted(Comparator.comparingInt(String::length).thenComparing(Comparator.naturalOrder())).collect(Collectors.toList());System.out.println(collect2);//[a, bb, cc, ddd]

将流转换为集合

转换为list

        List collect = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu", "zhouqi").collect(Collectors.toList());

转换为LinkedList

        LinkedList collect2 = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu", "zhouqi", "lisi").collect(Collectors.toCollection(LinkedList::new));

转换为set

        Set collect1 = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu", "zhouqi","lisi").collect(Collectors.toSet());System.out.println(collect1);//[lisi, zhouqi, zhaoliu, zhangsan, wangwu]

转换为Array

        String[] strings = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu", "zhouqi").toArray(String[]::new);

转换为Map

        List userList = new ArrayList<>();userList.add(new User("霸道",30));userList.add(new User("的",40));userList.add(new User("程序猿",50));userList.add(new User("张三",60));userList.add(new User("李四",70));Map collect3 = userList.stream().collect(Collectors.toMap(User::getAge, User::getName));System.out.println(collect3);//{50=程序猿, 70=李四, 40=的, 60=张三, 30=霸道}

转换为Map,键为对象属性,值为对象本身

方式一

        Map collect4 = userList1.stream().collect(Collectors.toMap(User::getId, b -> b));System.out.println(collect4);

方式二

        Map collect5 = userList1.stream().collect(Collectors.toMap(User::getId, Function.identity()));System.out.println(collect5);

对Map排序与分组

根据键或值对Map排序

Stream names = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu", "zhouqi", "a", "a", "aa", "bbb", "ccc");
Map> collect1 = names.collect(Collectors.groupingBy(String::length));
System.out.println(collect1);//{1=[a, a], 2=[aa], 3=[bbb, ccc], 4=[lisi], 6=[wangwu, zhouqi], 7=[zhaoliu], 8=[zhangsan]}

Collectors.groupingBy 方法传入 Function 作为第一个参数,表示分类器(classifier)。

在本例中,分类器是每个字符串的长度。如果 groupingBy 方法只传入一个参数,则结果为 Map,

其中键为分类器的值,值为匹配分类器的元素列表。

双参数形式的groupingBy方法传入另一个Collector,它称为下游收集器,用于对名字列表进行后期处理,这种情况下返回的是Map

Map collect = names1.collect(Collectors.groupingBy(String::length, Collectors.counting()));
System.out.println(collect);//{1=2, 2=1, 3=2, 4=1, 6=2, 7=1, 8=1}

上面按照名字长度的升序输出,如果希望按照降序,可以使用Map.Entry接口的comparingByKey方法

        Stream names2 = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu", "zhouqi", "a", "a", "aa", "bbb", "ccc");Map collect2 = names2.collect(Collectors.groupingBy(String::length, Collectors.counting()));collect2.entrySet().stream().sorted(Map.Entry.comparingByKey(Comparator.reverseOrder())).forEach(e -> System.out.println(e.getKey() +" "+ e.getValue()));

comparingByKey 方法返回一个根据键进行排序的比较器。如果希望以键的相反顺序排序,

可以使用comparingByKey方法的重载形式,它传入比较器作为参数。

Stream.sorted 方法生成一个新的排序流,它不对源数据进行修改。换言之,原始 Map 不受影响。

分区

用户希望将元素集合分成若干个类别

假设存在一个字符串集合,可以通过partitioningBy方法将这些字符串按照偶数长度和奇数长度进行划分

        List stringList = Arrays.asList("a", "bbb", "cc", "ddddd", "eeee");Map> collect = stringList.stream().collect(Collectors.partitioningBy(s -> s.length() % 2 == 0));collect.forEach((key,value) -> System.out.printf("%5s: %s%n",key,value));

Collectors.partitioningBy 方法将元素拆分为满足Predicate 与不满足 Predicate 的两类。

输出结果:

        //false: [a, bbb, ddddd]
        // true: [cc, eeee]

如果对每个类别包含多少元素更感兴趣,可以使用partitioningBy方法的重载方法(第二个参数为Collector类型)

        List stringList1 = Arrays.asList("a", "bbb", "cc", "ddddd", "eeee");Map collect1 = stringList1.stream().collect(Collectors.partitioningBy(s -> s.length() % 2 == 0, Collectors.counting()));collect1.forEach((k,v)->System.out.printf("%5s: %d%n",k,v));

输出结果:

        //false: 3
        // true: 2

查找最大值和最小值

用户希望确定流中的最大值或最小值

方法一:使用 BinaryOperator 接口定义的 maxBy 和 minBy 方法

        List userList1 = new ArrayList<>();userList1.add(new User(1,"霸道",30));userList1.add(new User(2,"的",40));userList1.add(new User(3,"程序猿",50));userList1.add(new User(4,"张三",60));userList1.add(new User(5,"李四",70));//默认用户-流为空时的默认值User defaultUser = new User(0,"默认名字",0);//实现方式1//BinaryOperator 是 java.util.function 包定义的一种函数式接口,它继承自 BiFunction 接口,适合在函数和返回值的参数属于同一个类时使用。Optional reduce = userList1.stream().reduce(BinaryOperator.maxBy(Comparator.comparingInt(User::getAge)));System.out.println("年龄最大的为:"+reduce.orElse(defaultUser).getName());

方法二:使用 Stream 接口定义的 max 和 min 方法

        Optional max = userList1.stream().max(Comparator.comparingInt(User::getAge));

如果直接获取年龄值

        OptionalInt max1 = userList1.stream().mapToInt(User::getAge).max();

方法三:使用 Collectors 类定义的 maxBy 和 minBy 方法。

        Optional collect = userList1.stream().collect(Collectors.maxBy(Comparator.comparingInt(User::getAge)));

相关内容

热门资讯

【看表情包学Linux】进程地...   🤣 爆笑教程 👉 《看表情包学Linux》👈 猛...
育碧GDC2018程序化大世界... 1.传统手动绘制森林的问题 采用手动绘制的方法的话,每次迭代地形都要手动再绘制森林。这...
编译原理陈火旺版第三章课后题答... 下面答案仅供参考! 1.编写一个对于 Pascal 源程序的预处理程序。该程序的作用是...
MacBookPro M2芯片... MacBookPro M2芯片下如何搭建React-Native环境目录软件下载环境配置 目录 写在...
Android studio ... 解决 Android studio 出现“The emulator process for AVD ...
pyflink学习笔记(六):... 在pyflink学习笔记(一)中简单介绍了table-sql的窗口函数,下面简单介绍下...
创建deployment 创建deployment服务编排-DeploymentDeployment工作负载均衡器介绍Depl...
gma 1.1.4 (2023... 新增   1、地图工具    a. 增加【GetWorldDEMDataSet】。提供了一套 GEO...
AI专业教您保姆级在暗影精灵8... 目录 一、Stable Diffusion介绍    二、Stable Diffusion环境搭建 ...
vue笔记 第一个Vue应用 Document{{content}}{{...
Unity自带类 --- Ti... 1.在Unity中,自己写的类(脚本)的名字不能与Unit...
托福口语21天——day5 发... 目录 一、连读纠音 二、语料输入+造句输出 三、真题 一、连读纠音 英语中的连读方式有好几种...
五、排序与分页 一、排序 1、语法 ORDER BY 字段 ASC | DESC ASC(ascen...
Linux系统中如何安装软件 文章目录一、rpm包安装方式步骤:二、deb包安装方式步骤:三、tar....
开荒手册4——Related ... 0 写在前面 最早读文献的时候,每每看到related work部分都会选择性的忽略&...
实验01:吃鸡蛋问题 1.实验目的: 通过实验理解算法的概念、算法的表示、算法的时间复杂度和空间复杂度分析&...
8个免费图片/照片压缩工具帮您... 继续查看一些最好的图像压缩工具,以提升用户体验和存储空间以及网站使用支持。 无数图像压...
Spring Cloud Al... 前言 本文小新为大家带来 Sentinel控制台规则配置 相关知识,具体内容包括流控...
多项目同时进行,如何做好进度管... 多项目同时进行,如何做好进度管理? 大多数时候,面对项目进...
ATTCK红队评估实战靶场(二... 前言 第二个靶机来喽,地址:vulunstack 环境配置 大喊一声我...