公众号「架构成长指南」,专注于生产实践、云原生、分布式系统、大数据技术分享。
在本教程中,您将通过大量示例来学习 Java 8 Stream API。
Java 在 Java 8 中提供了一个新的附加包,称为 java.util.stream。该包由类、接口和枚举组成,允许对元素进行函数式操作。 您可以通过在程序中导入 java.util.stream包来使用流。
Stream提供以下功能:
Stream不存储元素。它只是通过计算操作的管道传送来自数据结构、数组或 I/O 通道等源的元素。
Stream本质上是函数式的,对流执行的操作不会修改其源。例如,过滤从集合获取的 Stream 会生成一个没有过滤元素的新 Stream,而不是从源集合中删除元素。
Stream是惰性的,仅在需要时才计算代码,在流的生命周期中,流的元素仅被访问一次。
与迭代器一样,必须生成新流才能重新访问源中的相同元素。
您可以使用 Stream 来 过滤、收集、打印以及 从一种数据结构转换为其他数据结构等。

Stream API 示例
1. 创建一个空的Stream
在创建空流时,应使用 empty() 方法:- Stream<String> stream = Stream.empty();
- stream.forEach(System.out::println);
复制代码 通常情况下,在创建时会使用 empty() 方法,以避免在没有元素的流中返回 null:- public Stream<String> streamOf(List<String> list) {
- return list == null || list.isEmpty() ? Stream.empty() : list.stream();
- }
复制代码 2.从集合中创建流
- import java.io.IOException;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Set;
- import java.util.stream.Stream;
- public class StreamCreationExamples {
- public static void main(String[] args) throws IOException {
- Collection<String> collection = Arrays.asList("JAVA", "J2EE", "Spring", "Hibernate");
- Stream<String> stream2 = collection.stream();
- stream2.forEach(System.out::println);
- List<String> list = Arrays.asList("JAVA", "J2EE", "Spring", "Hibernate");
- Stream<String> stream3 = list.stream();
- stream3.forEach(System.out::println);
- Set<String> set = new HashSet<>(list);
- Stream<String> stream4 = set.stream();
- stream4.forEach(System.out::println);
- }
- }
复制代码 输出- JAVA
- J2EE
- Spring
- Hibernate
- JAVA
- J2EE
- Spring
- Hibernate
- JAVA
- Hibernate
- J2EE
- Spring
复制代码 3. 从数组中创建流对象
数组可以是流的源,也可以从现有数组或数组的一部分创建数组:- import java.util.Arrays;
- import java.util.stream.Stream;
- public class StreamCreationExample {
- public static void main(String[] args) {
- // 使用Arrays.stream()创建流
- int[] numbers = {1, 2, 3, 4, 5};
- Stream<Integer> stream1 = Arrays.stream(numbers);
- System.out.println("Using Arrays.stream():");
- stream1.forEach(System.out::println);
- // 使用Stream.of()创建流
- String[] names = {"Alice", "Bob", "Charlie"};
- Stream<String> stream2 = Stream.of(names);
- System.out.println("Using Stream.of():");
- stream2.forEach(System.out::println);
- // 使用Stream.builder()创建流
- String[] colors = {"Red", "Green", "Blue"};
- Stream.Builder<String> builder = Stream.builder();
- for (String color : colors) {
- builder.add(color);
- }
- Stream<String> stream3 = builder.build();
- System.out.println("Using Stream.builder():");
- stream3.forEach(System.out::println);
- }
- }
复制代码 输出- Using Arrays.stream():
- 1
- 2
- 3
- 4
- 5
- Using Stream.of():
- Alice
- Bob
- Charlie
- Using Stream.builder():
- Red
- Green
- Blue
复制代码 4. 使用Stream过滤一个集合示例
在下面的示例中,我们不使用流过滤数据,看看代码是什么样的,同时我们在给出一个使用stream过滤的示例,对比一下
不使用Stream过滤一个集合示例- import java.util.ArrayList;
- import java.util.List;
- public class FilterWithoutStreamExample {
- public static void main(String[] args) {
- List<Integer> numbers = new ArrayList<>();
- numbers.add(10);
- numbers.add(20);
- numbers.add(30);
- numbers.add(40);
- numbers.add(50);
- List<Integer> filteredNumbers = new ArrayList<>();
- for (Integer number : numbers) {
- if (number > 30) {
- filteredNumbers.add(number);
- }
- }
- System.out.println("Filtered numbers (without Stream):");
- for (Integer number : filteredNumbers) {
- System.out.println(number);
- }
- }
- }
复制代码 输出:- Filtered numbers (without Stream):
- 40
- 50
复制代码 使用 Stream 过滤集合示例:- import java.util.ArrayList;
- import java.util.List;
- public class FilterWithStreamExample {
- public static void main(String[] args) {
- List<Integer> numbers = new ArrayList<>();
- numbers.add(10);
- numbers.add(20);
- numbers.add(30);
- numbers.add(40);
- numbers.add(50);
- List<Integer> filteredNumbers = numbers.stream()
- .filter(number -> number > 30)
- .toList();
- System.out.println("Filtered numbers (with Stream):");
- filteredNumbers.forEach(System.out::println);
- }
- }
复制代码 输出:- Filtered numbers (with Stream):
- 40
- 50
复制代码 前后我们对比一下,可以看到,使用 Stream 进行集合过滤可以更加简洁和直观,减少了手动迭代和添加元素的步骤。它提供了一种声明式的编程风格,使代码更易读、可维护和可扩展。
5. 使用Stream过滤和遍历集合
在下面的示例中,我们使用 filter() 方法进行过滤,使用 forEach() 方法对数据流进行迭代:- import java.util.ArrayList;
- import java.util.List;
- public class FilterAndIterateWithStreamExample {
- public static void main(String[] args) {
- List<String> names = new ArrayList<>();
- names.add("Alice");
- names.add("Bob");
- names.add("Charlie");
- names.add("David");
- names.add("Eve");
- System.out.println("Filtered names starting with 'A':");
- names.stream()
- .filter(name -> name.startsWith("A"))
- .forEach(System.out::println);
- }
- }
复制代码 输出- Filtered names starting with 'A':
- Alice
复制代码 在上述示例中,我们有一个字符串列表 names,其中包含了一些名字。
我们使用 Stream 进行过滤和迭代操作以查找以字母 "A" 开头的名字。
6.使用Collectors方法求和
我们还可以使用Collectors计算数值之和。
在下面的示例中,我们使用Collectors类及其指定方法计算所有产品价格的总和。- import java.util.ArrayList;
- import java.util.List;
- import java.util.stream.Collectors;
- public class SumByUsingCollectorsMethods {
- public static void main(String[] args) {
- List < Product > productsList = new ArrayList < Product > ();
- productsList.add(new Product(1, "HP Laptop", 25000f));
- productsList.add(new Product(2, "Dell Laptop", 30000f));
- productsList.add(new Product(3, "Lenevo Laptop", 28000f));
- productsList.add(new Product(4, "Sony Laptop", 28000f));
- productsList.add(new Product(5, "Apple Laptop", 90000f));
-
- double totalPrice3 = productsList.stream()
- .collect(Collectors.summingDouble(product -> product.getPrice()));
- System.out.println(totalPrice3);
- }
- }
复制代码 输出7. 使用Stream查找年龄最大和最小的学生
假设有一个 Student 类具有 name 和 age 属性。我们可以使用 Stream 来查找学生集合中年龄的最大和最小值,并打印出相应的学生信息。以下是一个示例:- import java.util.ArrayList;
- import java.util.Comparator;
- import java.util.List;
- import java.util.Optional;
- public class StudentStreamExample {
- public static void main(String[] args) {
- List<Student> students = new ArrayList<>();
- students.add(new Student("Alice", 20));
- students.add(new Student("Bob", 22));
- students.add(new Student("Charlie", 19));
- students.add(new Student("David", 21));
- // 查找年龄最大的学生
- Optional<Student> maxAgeStudent = students.stream()
- .max(Comparator.comparingInt(Student::getAge));
- // 查找年龄最小的学生
- Optional<Student> minAgeStudent = students.stream()
- .min(Comparator.comparingInt(Student::getAge));
- // 打印最大和最小年龄的学生信息
- System.out.println("Student with maximum age:");
- maxAgeStudent.ifPresent(System.out::println);
- System.out.println("Student with minimum age:");
- minAgeStudent.ifPresent(System.out::println);
- }
- }
- class Student {
- private String name;
- private int age;
- public Student(String name, int age) {
- this.name = name;
- this.age = age;
- }
- public String getName() {
- return name;
- }
- public int getAge() {
- return age;
- }
- @Override
- public String toString() {
- return "Student{" +
- "name='" + name + '\'' +
- ", age=" + age +
- '}';
- }
- }
复制代码 输出:- Student with maximum age:
- Student{name='Bob', age=22}
- Student with minimum age:
- Student{name='Charlie', age=19}
复制代码 8. 使用Stream转换List为Map
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Map;
- import java.util.stream.Collectors;
- public class StudentStreamToMapExample {
- public static void main(String[] args) {
- List<Student> students = new ArrayList<>();
- students.add(new Student("Alice", 20));
- students.add(new Student("Bob", 22));
- students.add(new Student("Charlie", 19));
- students.add(new Student("David", 21));
- // 将学生列表转换为 Map,以姓名为键,学生对象为值
- Map<String, Student> studentMap = students.stream()
- .collect(Collectors.toMap(Student::getName, student -> student));
- // 打印学生 Map
- for (Map.Entry<String, Student> entry : studentMap.entrySet()) {
- System.out.println(entry.getKey() + ": " + entry.getValue());
- }
- }
- }
- class Student {
- private String name;
- private int age;
- public Student(String name, int age) {
- this.name = name;
- this.age = age;
- }
- public String getName() {
- return name;
- }
- public int getAge() {
- return age;
- }
- @Override
- public String toString() {
- return "Student{" +
- "name='" + name + '\'' +
- ", age=" + age +
- '}';
- }
- }
复制代码 输出- David: Student{name='David', age=21}
- Bob: Student{name='Bob', age=22}
- Charlie: Student{name='Charlie', age=19}
- Alice: Student{name='Alice', age=20}
复制代码 在上面示例中,我们使用Collectors.toMap() 方法将学生列表转换为 Map。我们指定了键提取器 Student::getName,将学生的姓名作为键。对于值提取器,我们使用了一个匿名函数 student -> student,它返回学生对象本身作为值。
9. 使用Stream把List对象转换为另一个List对象
假设我们有一个 Person 类,其中包含姓名和年龄属性。我们可以使用 Stream 来将一个 List 对象转换为另一个 List 对象,其中只包含人员的姓名。以下是一个示例:- import java.util.ArrayList;
- import java.util.List;
- import java.util.stream.Collectors;
- public class ListTransformationExample {
- public static void main(String[] args) {
- List<Person> persons = new ArrayList<>();
- persons.add(new Person("Alice", 20));
- persons.add(new Person("Bob", 22));
- persons.add(new Person("Charlie", 19));
- // 将 Person 列表转换为只包含姓名的 String 列表
- List<String> names = persons.stream()
- .map(Person::getName)
- .collect(Collectors.toList());
- // 打印转换后的姓名列表
- System.out.println(names);
- }
- }
- class Person {
- private String name;
- private int age;
- public Person(String name, int age) {
- this.name = name;
- this.age = age;
- }
- public String getName() {
- return name;
- }
- public int getAge() {
- return age;
- }
- }
复制代码 输出:在上述示例中,我们有一个 Person 类,其中包含姓名和年龄属性。我们创建了一个 persons 列表,并添加了几个 Person 对象。
使用Stream,我们通过调用 map() 方法并传入一个方法引用 Person::getName,最后,我们使用 collect() 方法和 Collectors.toList() 将转换后的姓名收集到一个新的列表中。
API
https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |