引言
Java Stream API 自 Java 8 引入以来,已成为处理集合数据的强大工具。它不仅提高了代码的可读性,还优化了性能,使得集合操作变得更加简洁和高效。本文将深入探讨如何利用 Stream API 的常用操作,帮助你更好地掌握这一强大的功能。
Java Stream API 简介
Java Stream 是 Java 8 引入的一种新的抽象层,专门用于简化集合对象的处理过程。它提供了一种更加简洁和函数式的方式来处理数据,使得开发者能够编写出更加清晰和易于维护的代码。Stream 操作可以是中间操作,也可以是终端操作,中间操作返回的是Stream,所以我们可以链式调用;终端操作返回的是一个结果或者是null。
示例:
假设我们有一个 Person
类,其中包含 name
和 age
两个属性,现在我们有一个 Person
对象的列表,我们想要找出其中年龄大于20的所有人,并按照年龄升序排序。
List<Person> people = Arrays.asList(new Person("Alice", 23),new Person("Bob", 20),new Person("Charlie", 24)
);
// 使用Stream进行过滤和排序
List<Person> result = people.stream()
.filter(person -> person.getAge() > 20) // 过滤出年龄大于20的人
.sorted(Comparator.comparing(Person::getAge)) // 根据年龄升序排序
.collect(Collectors.toList()); // 收集结果到一个列表中
// 输出结果
result.forEach(System.out::println);
在这个示例中,我们首先创建了一个包含三个 Person
对象的列表。然后,我们调用 stream()
方法将列表转换为 Stream。接下来,我们使用 filter
方法来过滤出年龄大于20的人,使用 sorted
方法根据年龄进行升序排序,最后使用 collect
方法将结果收集到一个新的列表中。
超级常用操作
求交集和差集
通过使用 filter 和 map 方法,我们可以轻松地实现这些集合操作,从而提高代码的可读性和效率。
示例:
假设我们有两个整数列表,我们想要找出这两个列表的交集和差集。
List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> list2 = Arrays.asList(4, 5, 6, 7, 8);// 求交集
List<Integer> intersection = list1.stream().filter(list2::contains) // 筛选出同时存在于list2中的元素.collect(Collectors.toList()); // 收集结果到一个新的列表System.out.println("交集: " + intersection);// 求差集
List<Integer> difference = list1.stream().filter(element -> !list2.contains(element)) // 筛选出不存在于list2中的元素.collect(Collectors.toList()); // 收集结果到一个新的列表System.out.println("差集: " + difference);
在这个示例中,我们首先定义了两个整数列表 list1
和 list2
。然后,我们使用 stream()
方法将 list1
转换为 Stream。接下来,我们使用 filter
方法来筛选出同时存在于 list2
中的元素,从而得到两个列表的交集。同样地,我们使用 filter
方法来筛选出不存在于 list2
中的元素,从而得到 list1
相对于 list2
的差集。最后,我们使用 collect
方法将结果收集到新的列表中,并打印出交集和差集。
排序
在Java的Stream API中,sorted()
方法提供了一种快捷且灵活的方式来对集合中的元素进行排序。这个方法可以直接对元素进行自然排序,或者通过提供一个自定义的比较器来实现定制排序。这种操作对于处理大量数据时尤其有用,因为它允许开发者以声明式的方式来表达排序逻辑,而不是手动实现排序算法。
- 示例:
假设我们有一个学生列表,每个学生都有姓名和分数两个属性,我们想要根据分数对学生进行升序排序。
List<Student> students = Arrays.asList(new Student("Alice", 90),new Student("Bob", 85),new Student("Charlie", 92)
);
// 使用Stream进行排序
List<Student> sortedStudents = students.stream().sorted(Comparator.comparingInt(Student::getScore)) // 根据分数进行升序排序.collect(Collectors.toList()); // 收集排序后的结果
// 输出排序后的学生信息sortedStudents.forEach(student -> System.out.println(student.getName() + ": " + student.getScore()));
在这个示例中,我们首先创建了一个包含三个 Student
对象的列表。然后,我们调用 stream()
方法将列表转换为 Stream。接下来,我们使用 sorted
方法并提供一个比较器,根据学生的分数进行升序排序。最后,我们使用 collect
方法将排序后的结果收集到一个新的列表中,并打印出每个学生的姓名和分数。
Stream.Builder
Stream.Builder 是 Java 8 引入的一个接口,用于更灵活地构建 Stream 流。与直接从集合或数组创建流相比,Stream.Builder 提供了一种逐个添加元素的方式,使得我们可以在构建流的过程中动态地添加元素,这在处理动态数据源或需要在运行时决定元素的场景下非常有用。
示例:
考虑一个场景,我们需要创建一个字符串流,并对这个流进行一系列的操作。我们可以使用 Stream.Builder 来逐个添加字符串元素,然后构建成一个流。
在这个示例中,我们首先创建了一个 Stream.Builder 对象,然后使用 add 方法逐个添加了三个字符串元素。最后,我们调用 build 方法构建了一个流,并对这个流进行了遍历打印操作。
// 导入必要的类
import java.util.stream.Stream;// 主类定义
public class StreamBuilderExample {// 主函数public static void main(String[] args) {// 创建一个 Stream.Builder 对象Stream.Builder<String> builder = Stream.builder();// 逐个添加字符串元素到流构建器builder.add("zhangsan"); // 添加张三builder.add("lisi"); // 添加李四builder.add("wangmazi"); // 添加王麻子// 构建并获取流Stream<String> stream = builder.build();// 遍历流,打印每个元素stream.forEach(System.out::println);}
}
从数组创建流
可以使用Arrays.stream()
方法从数组创建流。
示例:
-
假设有一个整数数组,我们想要找出其中的偶数,并将其乘以2。
-
原始数组:
[1, 2, 3, 4, 5, 6]
-
操作后的结果:
[4, 8, 12]
-
代码片段:
// 引入必要的包 import java.util.Arrays; import java.util.List; import java.util.stream.Collectors;public class ArrayToStream {public static void main(String[] args) {// 定义一个整数数组int[] numbers = {1, 2, 3, 4, 5, 6};// 使用Arrays.stream()方法从数组创建流,然后进行过滤和映射操作List<Integer> result = Arrays.stream(numbers).filter(n -> n % 2 == 0) // 过滤出偶数.map(n -> n * 2) // 将偶数乘以2.boxed() // 将IntStream转换为Stream<Integer>.collect(Collectors.toList()); // 将结果收集到列表中// 输出结果System.out.println(result); // 输出:[4, 8, 12]} }
从集合创建流
可以通过调用集合的stream()
方法直接获取一个流对象。
示例:
-
假设有一个人名列表,我们想要找出长度大于3的人名,并将其转换为大写。
-
原始列表:
["Tom", "Jerry", "Alice", "Bob", "Catherine"]
-
操作后的结果:
["JERRY", "ALICE", "CATHERINE"]
-
代码片段:
List<String> names = Arrays.asList("Tom", "Jerry", "Alice", "Bob", "Catherine"); List<String> filteredNames = names.stream().filter(name -> name.length() > 3).map(String::toUpperCase).collect(Collectors.toList());
迭代中使用元素索引
在Java 8的Stream API中,直接获取正在迭代的元素的索引并不是一件直接的事情。但是,我们可以通过一些间接的方法来实现这一点,比如使用 IntStream
和 mapToObj
方法。这样做不仅使代码更加灵活,而且还保持了代码的简洁性和可读性。
示例:
假设我们有一个字符串列表,我们想要打印出每个字符串及其在列表中的索引。
List<String> words = Arrays.asList("zhangsan", "lisi", "wangmazi");// 使用IntStream和mapToObj进行迭代
IntStream.range(0, words.size()).mapToObj(index -> "索引: " + index + ", 值: " + words.get(index)) // 获取索引和对应的值.forEach(System.out::println); // 打印结果
在这个示例中,我们首先定义了一个包含三个字符串的列表 words
。然后,我们使用 IntStream.range
方法创建一个从0到 words.size()
的整数流,其中每个整数代表一个索引。接下来,我们使用 mapToObj
方法将每个索引映射到一个字符串,这个字符串包含索引和对应的列表元素。最后,我们使用 forEach
方法来打印出结果。
总结
通过本文的介绍,你应该已经掌握了如何使用 Java Stream API 进行集合操作,包括求交集和差集等。掌握这些技能不仅能够提升你的编程效率,还能帮助你写出更加简洁、高效的代码。
最近很多小伙伴,让我帮忙找一套 Java 学习资料,于是我翻遍了收藏的 1024G 资料,找到一套华为工程师总结的 Java 笔记,可以说是 Java 程序员必备!
整个资料包内容专注 Java 技术,包括 Spring、Spring Boot/Cloud、Dubbo、JVM、集合、多线程、JPA、MyBatis、MySQL、大数据、Nginx、Git、Docker、GitHub、Servlet、JavaWeb、IDEA、Redis、算法、面试题等几乎覆盖了 Java 基础和进阶的方方面面,非常适合初学者入门和进阶者巩固知识!
据说已经有小伙伴通过这套资料,成功的入职了蚂蚁金服、今日头条等大厂。而且,这些资料不是扫描版的,里面的文字都可以直接复制,非常便于我们学习!
分享在这里~
链接:https://pan.baidu.com/s/1qPcZxxoMUqEGhxNLNusdaQ?pwd=lird
提取码:lird