跳转至

Java Stream 示例详解

简介

在 Java 8 中,Stream API 作为一个强大的新特性被引入,它为处理集合数据提供了一种更加简洁、高效和声明式的方式。Stream 可以让我们以函数式编程的风格对数据进行过滤、映射、归约等操作,极大地提升了代码的可读性和可维护性。本文将通过丰富的示例深入探讨 Java Stream 的基础概念、使用方法、常见实践以及最佳实践。

目录

  1. 基础概念
  2. 使用方法
    • 创建 Stream
    • 中间操作
    • 终端操作
  3. 常见实践
    • 过滤数据
    • 映射数据
    • 数据归约
  4. 最佳实践
  5. 小结
  6. 参考资料

基础概念

Stream 是 Java 8 引入的一种新的抽象概念,它代表了一组支持顺序和并行聚合操作的元素序列。与集合不同,Stream 本身并不存储数据,它只是对数据源(如集合、数组等)进行操作。Stream 的操作可以分为中间操作和终端操作: - 中间操作:返回一个新的 Stream,允许链式调用多个中间操作。例如 filtermap 等。 - 终端操作:执行 Stream 上的操作并返回结果,之后 Stream 就会被消耗,不能再被使用。例如 forEachcollect 等。

使用方法

创建 Stream

  1. 从集合创建 ```java import java.util.Arrays; import java.util.List; import java.util.stream.Stream;

    public class StreamExample { public static void main(String[] args) { List numbers = Arrays.asList(1, 2, 3, 4, 5); Stream streamFromList = numbers.stream(); Stream parallelStreamFromList = numbers.parallelStream(); } } 2. **从数组创建**java int[] intArray = {1, 2, 3, 4, 5}; IntStream streamFromArray = Arrays.stream(intArray); 3. **使用 `Stream.of` 方法创建**java Stream streamFromString = Stream.of("apple", "banana", "cherry"); ```

中间操作

  1. 过滤(filter:根据条件过滤 Stream 中的元素。 java List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); Stream<Integer> filteredStream = numbers.stream() .filter(number -> number % 2 == 0);
  2. 映射(map:将 Stream 中的每个元素映射为一个新的元素。 java List<String> words = Arrays.asList("apple", "banana", "cherry"); Stream<Integer> lengthStream = words.stream() .map(String::length);
  3. 排序(sorted:对 Stream 中的元素进行排序。 java List<Integer> numbers = Arrays.asList(5, 3, 1, 4, 2); Stream<Integer> sortedStream = numbers.stream() .sorted();

终端操作

  1. 遍历(forEach:对 Stream 中的每个元素执行给定的操作。 java List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); numbers.stream() .forEach(System.out::println);
  2. 收集(collect:将 Stream 中的元素收集到一个集合中。 java List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); List<Integer> evenNumbers = numbers.stream() .filter(number -> number % 2 == 0) .collect(Collectors.toList());
  3. 归约(reduce:将 Stream 中的元素归约为一个值。 java List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); Optional<Integer> sum = numbers.stream() .reduce((a, b) -> a + b);

常见实践

过滤数据

假设我们有一个员工列表,需要过滤出年龄大于 30 岁的员工。

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

class Employee {
    private String name;
    private int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class FilterEmployeeExample {
    public static void main(String[] args) {
        List<Employee> employees = new ArrayList<>();
        employees.add(new Employee("Alice", 25));
        employees.add(new Employee("Bob", 35));
        employees.add(new Employee("Charlie", 40));

        List<Employee> filteredEmployees = employees.stream()
              .filter(employee -> employee.getAge() > 30)
              .collect(Collectors.toList());

        filteredEmployees.forEach(System.out::println);
    }
}

映射数据

将一个字符串列表中的每个字符串转换为大写形式。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class MapStringExample {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("apple", "banana", "cherry");
        List<String> upperCaseWords = words.stream()
              .map(String::toUpperCase)
              .collect(Collectors.toList());

        upperCaseWords.forEach(System.out::println);
    }
}

数据归约

计算一个整数列表的总和。

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class ReduceExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        Optional<Integer> sum = numbers.stream()
              .reduce((a, b) -> a + b);

        sum.ifPresent(System.out::println);
    }
}

最佳实践

  1. 避免不必要的中间操作:过多的中间操作可能会影响性能,尽量简化 Stream 操作链。
  2. 合理使用并行流:并行流可以提高处理大数据集的效率,但在某些情况下,顺序流可能更合适。需要根据具体情况进行性能测试。
  3. 使用 Optional 处理可能为空的结果:在使用终端操作(如 reduce)时,返回的结果可能为空,使用 Optional 可以避免空指针异常。

小结

Java Stream API 为处理集合数据提供了一种强大而灵活的方式。通过理解基础概念、掌握使用方法以及遵循最佳实践,我们可以编写更加简洁、高效和可读的代码。Stream 的中间操作和终端操作组合可以满足各种数据处理需求,无论是过滤、映射还是归约数据。希望本文的示例和讲解能帮助读者更好地理解和应用 Java Stream。

参考资料