集合处理常用Stream流

news2024/11/18 15:29:54

集合处理常用Stream流

  • 1、Stream API介绍
  • 2、List集合常用Stream方法

stream流经常使用,但是遇到一些流操作时,会一下想不到用哪种,这里总结一下,方便自己或者读者查找

1、Stream API介绍

Stream API是Java 8引入的一项重要特性,它提供了一种新的处理集合数据的方式。Stream可以看作是一种高级的迭代器,它允许以声明式的方式对集合进行各种操作,如过滤、映射、排序、归约等。它可以简化集合处理的代码,并且在处理大数据集时具有性能优势。
个人理解:stream流就像一条源源不断的流水线或者管道,原材料从一端进入生产线,经过一系列的加工和处理,最终成品从另一端输出。在这个过程中,每个工人(方法)负责自己的任务,并将结果传递给下一个工人(方法),形成一个连续的操作链。直到遇到终止方法,才会生成最后的结果。

2、List集合常用Stream方法

1、stream(): 返回一个顺序流(Stream)。parallelStream(): 返回一个并行流(Stream)。

并行处理:Stream API提供了并行处理的能力,可以利用多线程来加速大数据集的处理。通过调用parallelStream()方法,可以将流转换为并行流,使得操作可以并行地执行。

List<String> list = Arrays.asList("apple", "banana", "cat");
Stream<String> stream = list.stream();
Stream<String> parallelStream = list.parallelStream();

2、filter(Predicate predicate): 过滤元素,保留符合条件的元素。传入是一个Predicate函数式接口,返回true:保留,false: 丢弃

List<String> list = Arrays.asList("apple", "banana", "cat");
Stream<String> filteredStream = list.stream().filter(s -> s.startsWith("a"));

3、distinct(): 去除重复的元素。

List<String> list = Arrays.asList("apple", "banana", "apple");
Stream<String> distinctStream = list.stream().distinct();

4、sorted(): 对元素进行排序,默认使用自然顺序。

List<Integer> list = Arrays.asList(3, 1, 2);
Stream<Integer> sortedStream = list.stream().sorted();

4.1 也可以自定义比较器,也就是参数中需要填写一个比较器 “sorted(Comparator<? super T> comparator)” 例如:

//字符串忽略大小写并排序
List<String> names = Arrays.asList("John", "Alice", "Bob", "Charlie");
List<String> sortedNames = names.stream().sorted((a, b) -> a.compareToIgnoreCase(b)).collect(Collectors.toList());

//对引用类型排序,通过其中的一个属性排序
class Person {
    private String name;
    private int age;

    // 省略构造函数和其他方法

    // Getter和Setter方法

    // ...
}
List<Person> persons = Arrays.asList(
        new Person("Alice", 25),
        new Person("Bob", 30),
        new Person("Charlie", 20)
);

List<Person> sortedPersons = persons.stream()
        .sorted(Comparator.comparingInt(Person::getAge))
        .collect(Collectors.toList());

5、limit(long maxSize): 限制流中元素的数量。

List<String> list = Arrays.asList("apple", "banana", "cat");
Stream<String> limitedStream = list.stream().limit(2);

6、forEach(Consumer action): 对每个元素执行给定的操作。就是遍历

List<String> list = Arrays.asList("apple", "banana", "cat");
list.stream().forEach(System.out::println);

7、map(Function<T, R> mapper): 将元素进行映射,得到一个新的流。这个不是转为一个map,该方法接受一个Function<T, R>函数接口作为参数,该函数接受一个输入类型为T的元素,并返回一个输出类型为R的结果。

List<String> list = Arrays.asList("apple", "banana", "cat");
Stream<Integer> lengthStream = list.stream().map(String::length);

7.1 map()方法允许我们在流中对每个元素进行自定义的转换操作,并生成一个新的流。通过传递适当的Function函数接口实现,我们可以实现各种转换操作,如类型转换、属性提取、计算转换等。例如:

class Person {
    private String name;
    // ...
}

List<Person> persons = Arrays.asList(
        new Person("Alice"),
        new Person("Bob"),
        new Person("Charlie")
);
//提取name,生成一个新的List<String>
List<String> names = persons.stream()
        .map(Person::getName)
        .collect(Collectors.toList());
//将一个person转换为一个student
 List<Student> students = persons.stream()
                .map(person -> {
                    String name = person.getName();
                    int age = person.getAge();
                    String school = getSchoolBasedOnAge(age); // 自定义的逻辑方法
                    return new Student(name, age, school);
                })
                .collect(Collectors.toList());
 private static String getSchoolBasedOnAge(int age) {
        if (age < 18) {
            return "High School";
        } else {
            return "University";
        }
    }

8、collect(Collector<? super T, A, R> collector): 将流中的元素收集到一个集合或其他可变结果容器中。最简单的就是返回一个新的List,上面方法都是

List<String> list = Arrays.asList("apple", "banana", "cat");
List<String> collectedList = list.stream().collect(Collectors.toList());

8.1、collect(Collector<? super T, A, R> collector) 是 Stream API 中的一个终端操作方法,用于将流中的元素收集到一个集合或其他可变结果容器中。该方法接受一个Collector对象作为参数,用于定义收集元素的规则。Collector对象可以通过Collectors工厂类的静态方法创建,也可以自定义实现。

Collector<? super T, A, R> 中的泛型参数表示以下内容:
T:表示流中的元素类型。? super T 表示任何 T 类型的超类型,这允许 Collector 处理 T 类型及其子类型的元素。
A:表示用于累积流元素的可变结果容器(accumulator)的类型。在收集过程中,Collector 将逐个元素累积到 A 类型的容器中。
R:表示收集操作的最终结果类型。Collector 最终将累积的结果转换为 R 类型,并返回结果。
在 Collector<? super T, A, R> 中,? super T 允许处理 T 类型及其子类型的元素。这种设计使得 Collector 更加通用,可以处理不同类型的元素,而不仅仅局限于 T 类型。累积结果容器的类型 A,以及收集操作的最终结果类型 R

例如:常用的list转map

public static void main(String[] args) {
        List<Person> persons = Arrays.asList(
                new Person("Alice", 25),
                new Person("Bob", 30),
                new Person("Charlie", 35)
        );

        Map<String, Integer> nameToAgeMap = persons.stream()
                .collect(Collectors.toMap(Person::getName, Person::getAge));

        System.out.println(nameToAgeMap);
    }

转为< id:实体 >

//在toMap()方法中,我们传递了三个参数:Person::getName用于提取姓名作为键,Function.identity()
//用于将Person对象本身作为值,以及一个合并函数 (existingValue, newValue) -> newValue 来处理
//重复的键。在合并函数中,我们选择使用新值作为合并后的值。
public static void main(String[] args) {
        List<Person> persons = Arrays.asList(
                new Person("Alice", 25),
                new Person("Bob", 30),
                new Person("Alice", 35)
        );

        Map<String, Person> nameToPersonMap = persons.stream()
                .collect(Collectors.toMap(Person::getName, Function.identity(), (existingValue, newValue) -> newValue));

        System.out.println(nameToPersonMap);
    }

8.2 使用collect()方法分组,以年龄分组

public static void main(String[] args) {
        List<Person> persons = Arrays.asList(
                new Person("Alice", 25),
                new Person("Bob", 30),
                new Person("Charlie", 35),
                new Person("Dave", 25)
        );

        Map<Integer, List<Person>> ageGroupMap = persons.stream()
                .collect(Collectors.groupingBy(Person::getAge));

        System.out.println(ageGroupMap);
    }

多层分组,根据城市和年龄进行多级分组。

public static void main(String[] args) {
        List<Person> persons = Arrays.asList(
                new Person("Alice", "New York", 25),
                new Person("Bob", "London", 30),
                new Person("Charlie", "New York", 35),
                new Person("Dave", "London", 25)
        );

        Map<String, Map<String, List<Person>>> cityToAgeGroupMap = persons.stream()
                .collect(Collectors.groupingBy(Person::getCity,
                        Collectors.groupingBy(person -> person.getAge() < 30 ? "Young" : "Old")));

        System.out.println(cityToAgeGroupMap);

得到了一个名为resultMap的嵌套的Map,其中外层的键是姓名,内层的键是年龄,值是对应的Person对象。

public static void main(String[] args) {
        List<Person> persons = Arrays.asList(
                new Person("Alice", 25),
                new Person("Bob", 30),
                new Person("Charlie", 35),
                new Person("Dave", 25)
        );

        Map<String, Map<Integer, Person>> resultMap = persons.stream()
                .collect(Collectors.groupingBy(
                        Person::getName,
                        Collectors.toMap(
                                Person::getAge,
                                person -> person
                        )
                ));

        System.out.println(resultMap);
    }

还可以做这些事情:

统计和汇总:
Collectors.counting(): 统计流中元素的数量。
Collectors.summingInt(toIntFunction): 对流中的元素进行整数求和。
Collectors.averagingInt(toIntFunction): 计算流中元素的平均值。
Collectors.summarizingInt(toIntFunction): 生成流中元素的汇总统计结果,包括数量、总和、平均值、最大值和最小值。

字符串拼接和连接:
Collectors.joining(): 将流中的元素按照指定的分隔符连接成一个字符串。
Collectors.joining(delimiter, prefix, suffix): 将流中的元素按照指定的分隔符、前缀和后缀连接成一个字符串。

9、allMatch(Predicate<? super T> predicate): 检查流中的所有元素是否都满足给定条件。返回boolean

List<Integer> list = Arrays.asList(2, 4, 6);
boolean allEven = list.stream().allMatch(n -> n % 2 == 0);

10、skip(long n): 跳过流中的前n个元素。这个可以用于列表分页
代码如下:跳过当前页前面的元素,然后再通过limit限制每页的大小
在这里插入图片描述
11、reduce(BinaryOperator accumulator): 根据给定的累加器函数对流中的元素进行归约操作。

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> sum = list.stream().reduce(0, (a, b) -> a + b);

找一个列表中年龄最大的Person

List<Person> people = Arrays.asList(
    new Person("John", 25),
    new Person("Alice", 30),
    new Person("Bob", 20)
);
Person oldestPerson = people.stream().reduce((p1, p2) -> p1.getAge() > p2.getAge() ? p1 : p2).orElse(null);

当然还可以做其他聚合和累积操作,具体在遇到聚合或者累加时,可以想到.reduce方法。

12、distinct(): 去除重复的元素。

List<String> list = Arrays.asList("apple", "banana", "apple");
Stream<String> distinctStream = list.stream().distinct();

13、flatMap(Function<? super T, ? extends Stream<? extends R>> mapper): 将流中的每个元素进行映射后扁平化成一个流。这个也是很好用的方法

List<List<Integer>> nestedList = Arrays.asList(Arrays.asList(1, 2), Arrays.asList(3, 4));
List<Integer> flattenedList = nestedList.stream().flatMap(Collection::stream).collect(Collectors.toList());

13.1、flatMap() 方法在处理嵌套结构、处理多个集合或流之间的映射关系时非常有用。它可以将嵌套的集合或流展开为一个更简单的结构,方便后续的处理和操作。

List<List<List<String>>> nestedList = Arrays.asList(
    Arrays.asList(
        Arrays.asList("apple", "banana"),
        Arrays.asList("cherry", "date")
    ),
    Arrays.asList(
        Arrays.asList("grape", "kiwi"),
        Arrays.asList("lemon", "mango")
    )
);

List<String> flattenedList = nestedList.stream()
    .flatMap(List::stream)
    .flatMap(List::stream)
    .collect(Collectors.toList());

System.out.println(flattenedList); // 输出:[apple, banana, cherry, date, grape, kiwi, lemon, mango]

假设有一个 Person 类型,其中每个人可以有多个爱好(hobbies)。每个爱好又可以有多个标签(tags)。我们可以使用 flatMap() 方法来处理这种嵌套的引用类型结构。

public static void main(String[] args) {
        List<Person> people = Arrays.asList(
                new Person("John", Arrays.asList("Reading", "Painting")),
                new Person("Alice", Arrays.asList("Music", "Cooking", "Hiking")),
                new Person("Bob", Arrays.asList("Photography"))
        );

        List<String> allHobbies = people.stream()
                .flatMap(person -> person.getHobbies().stream())
                .collect(Collectors.toList());

        System.out.println(allHobbies);
    }

使用 flatMap() 方法,我们将 people 列表中每个人的爱好(List)流化,并将它们扁平化成一个单一的流。最后,我们将流收集为一个列表 allHobbies,其中包含所有人的爱好。

后续有更好用的再补充。

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

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

相关文章

B. Nastya and Scoreboard(剪枝记忆化搜索)

Problem - 1340B - Codeforces Denis,在买了花和糖果之后&#xff08;你将在下一个任务中了解这个故事&#xff09;&#xff0c;与Nastya约会&#xff0c;向她表白要成为一对。现在&#xff0c;他们坐在咖啡馆里&#xff0c;最后... Denis请她答应在一起&#xff0c;但是... Na…

文盘 Rust -- tokio 绑定 cpu 实践

tokio 是 rust 生态中流行的异步运行时框架。在实际生产中我们如果希望 tokio 应用程序与特定的 cpu core 绑定该怎么处理呢&#xff1f;这次我们来聊聊这个话题。 首先我们先写一段简单的多任务程序。 use tokio::runtime; pub fn main() {let rt runtime::Builder::new_mu…

第48步 深度学习图像识别:RegNet建模(Pytorch)

基于WIN10的64位系统演示 一、写在前面 &#xff08;1&#xff09;RegNet RegNet (Regulated Networks) 是一种由 Facebook AI 的研究者们在 2020 年提出的神经网络架构&#xff0c;旨在探索网络架构设计的各种可能性&#xff0c;并找出最优的网络设计规则。RegNet 的核心理…

vue3ts分离头部变量单独一个ts

这里要说下 博主 vue^3.2.47 typescript^5.0.2 群有小伙伴说之前版本是不支持&#xff0c;所以你对下版本是不是比博主的版本低。 主要是页面代码太多&#xff0c;你看下面 然后博主就想着组合式开发 怎么把页面变干净点&#xff1a; 1、vue的就处理逻辑 2、ts就单纯定义…

vc++ 弹出打开、保存对话框功能(COM组件使用详解)

文章目录 前言一、原理二、代码封装三、使用示例C/C++实战入门到精通 https://blog.csdn.net/weixin_50964512/article/details/125710864 前言 很多应用都会有选择打开文件、或者选择保存文件的功能,这种情况下一般都是弹出一个对话框让用户自己选择。 这并不需要自己…

如何使用Scrum工具进行敏捷项目管理?

敏捷开发是一种轻量级的软件开发方式。 敏捷是一种通过创造变化和响应变化在不确定和混乱的环境中取得成功的能力。 敏捷开发是为了快速响应市场变化、通过自组织、跨职能团队 运用适合他们自身环境的实践进行演进得出解决方案。 所有符合敏捷宣言和敏捷开发十二项原则的方…

单片机要这样保护临界区

目录 一、概述 二、临界区保护测试场景 三、临界区保护三种实现 1、入门做法 2、改进做法 3、终极做法 四、附录---PRIMASK寄存器设置函数在各 IDE 下实现 一、概述 今天给大家分享的是Cortex-M裸机环境下&#xff0c;临界区保护的三种实现。 搞嵌入式玩过 RTOS 的小伙…

程序设计-编程题

CISP-PTE-编程题 2014 #include <iostream> using namespace std;double H(int n,double x) {if (n > 1)return 2 * x*H(n - 1, x) - 2 * (n - 1)*H(n - 2, x);if (n 0)return 1;if (n 1)return 2 * x; }int main() {int n;double x,result;cin >> n;cin >…

torch_geometric安装避坑

总流程&#xff1a; 1. 查看cuda, pytorch, python版本&#xff1b; 2. 依次安装torch_scatter, torch_sparse, torch_cluster, torch_spline&#xff1b; 3. 安装torch_geometric 一. 查看cuda, pytorch, python版本 可选方法如下图&#xff0c;其中该样例的cuda, pytorc…

注意力机制[矩阵]

每一个输入的向量( Embedding后的向量)&#xff0c;均有q,k,v,三个东西。其中q由下图所生成 I矩阵有a1,a2,a3,a4组成&#xff0c;Wq为权重矩阵&#xff0c;将I与Wq相乘求得Q(q1,q2,q3,q4)。K和V与I同理均可求得。 将求得出来的K&#xff0c;转置为竖向量与Q相乘&#xff0c;就…

【UE5 Cesium】12-Cesium for Unreal 去除左下角的icon

问题 在视口左下角的icon如何去除&#xff1f; 解决方法 打开“CesiumCreditSystemBP” 将“Credit Widget Class”一项中的“ScreenCredit”替换为“ScreenCreditWidget” 编译之后icon就不显示了。

戴尔游匣G16 7630原厂Win11系统带F12 Support Assist OS Recevory恢复功能

戴尔游匣G16 7630原厂Win11系统带F12 Support Assist OS Recevory恢复功能 各机型预装系统&#xff0c;带所有dell主题壁纸、dell软件驱动、带戴尔SupportAssist OS Recovery恢复功能&#xff0c;一次性恢复成新机状态&#xff0c;并且以后不用重装系统&#xff0c;直接恢复即…

MVC终极版

MVC终极版 1.把上次的代码打包为架包。2.通过basedao优化代码1.前言 3.后台代码servlet的优化。4前台代码展示 再次优化代码&#xff0c;上两次优化&#xff0c;都不是最完善的&#xff0c;这一次是最完善的了。 1.把上次的代码打包为架包。 选中两个文件&#xff0c;右键然后选…

Unreal 5 Lyra初学者游戏包概览笔记

Lyra初学者游戏包相关的官方视频有两个&#xff1a; Lyra初学者游戏包概览 https://www.bilibili.com/video/BV16B4y197Zy/Lyra跨平台UI开发 https://www.bilibili.com/video/BV1mT4y167Fm/ 这个笔记主要记录的是Lyra初学者包概览笔记的相关内容。里面介绍了如何创建关卡、输…

网络部署的思路

网络部署的思路——网络搭建的步骤 1.拓扑设计——IP地址的规划&#xff08;子网划分&#xff0c;子网汇总&#xff09; 2.实施 2.1 搭建拓扑 2.2 底层——给所有需要配置IP地址的网络节点&#xff0c;配置一个合法的IP地址 2.3 路由——全网可达 2.4 优化 策略——安全方面的…

【Linux初阶】基础IO - FILE结构体中的缓冲区

&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f; &#x1f36d;&#x1f36d;系列专栏&#xff1a;【Linux初阶】 ✒️✒️本篇内容&#xff1a;库函数和系统函数的刷新差异&#xff0c;缓冲区的意义、刷新策略、存在位置、文件写入的逻辑&#xff0c;缓冲…

Unity与iOS交互(1)——需要了解的IOS相关知识

【前言】 以下只是简要介绍&#xff0c;详细的内容需要自己去看链接 【Objective-C基础知识】 .h .m .mm .cpp文件区别 .h是头文件扩展名。头文件包含类&#xff0c;类型&#xff0c;函数和常数的声明&#xff0c;这里的定义一般是Public的 .m是实现文件扩展名。其包含源代…

云环境利用工具-----cf

简介 CF 是一个云环境利用框架&#xff0c;适用于在红队场景中对云上内网进行横向、SRC 场景中对 Access Key 即访问凭证的影响程度进行判定、企业场景中对自己的云上资产进行自检等等。 项目地址&#xff1a;https://github.com/teamssix/cf 使用手册&#xff1a;https://wi…

Java POI excel单元格背景色(填充)、字体颜色(对齐)、边框(颜色)、行高、列宽设置

文章目录 1、Excel Cell单元格背景色颜色名称对照关系2、Excel Cell单元格背景填充样式颜色填充对照关系3、Excel Cell字体样式设置对照图4、Excel 行高、列宽设置5、Excel单元格边框设置边框类型图片对比附一&#xff1a;一些问题1、关于列宽使用磅*20的计算方式2、关于行高使…

常用数据预处理与特征选择方法总结记录

在很多机器学习或者是深度学习建模之前&#xff0c;对于数据的处理尤为重要&#xff0c;选择合适的数据预处理方法和特征构建算法对于后续模型的结果有着很大的影响作用&#xff0c;这里的主要目的就是想记录总结汇总常用到的处理方法&#xff0c;学习备忘&#xff01; 数据清洗…