写点什么

Java Stream 中的 API 你都用过了吗?

作者:EquatorCoco
  • 2023-11-23
    福建
  • 本文字数:5731 字

    阅读完需:约 19 分钟

在本教程中,您将通过大量示例来学习 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); }}
复制代码


输出


JAVAJ2EESpringHibernateJAVAJ2EESpringHibernateJAVAHibernateJ2EESpring
复制代码


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():12345Using Stream.of():AliceBobCharlieUsing Stream.builder():RedGreenBlue
复制代码


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):4050
复制代码


使用 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):4050
复制代码


前后我们对比一下,可以看到,使用 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);
}}
复制代码


输出


201000.0
复制代码


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; }}
复制代码


输出:


  [Alice, Bob, Charlie]
复制代码


在上述示例中,我们有一个 Person 类,其中包含姓名和年龄属性。我们创建了一个 persons 列表,并添加了几个 Person 对象。


使用Stream,我们通过调用 map() 方法并传入一个方法引用 Person::getName,最后,我们使用 collect()方法和 Collectors.toList() 将转换后的姓名收集到一个新的列表中。


文章转载自:架构成长指南

原文链接:https://www.cnblogs.com/waldron/p/17848756.html

用户头像

EquatorCoco

关注

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
Java Stream中的API你都用过了吗?_Java_EquatorCoco_InfoQ写作社区