Java基础 - Java函数式编程 - Stream API

Introduction

函数式编程介绍

Stream API

Stream API的特性

  • 声明式: 你只需描述做什么,而无需关心如何做
  • 可组合: 中间操作返回一个新的Stream,因此可以将多个操作链接起来
  • 一次性消费: 一个Stream只能被一个终端操作消费一次
  • 支持并行化

Stream的创建

stream的创建:在使用Stream API之前,你必须先获得一个Stream实例。Collection接口提供了stream()parallelStream()默认方法。

1
2
3
4
5
6
7
8
9
10
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> sequentialStream = list.stream(); // 创建串行流

Set<Integer> set = new HashSet<>(Arrays.asList(1, 2, 3));
Stream<Integer> parallelStream = set.parallelStream(); // 创建并行流

String[] array = {"x", "y", "z"};
Stream<String> streamFromArray = Arrays.stream(array);
// 静态工厂方法创建
Stream<String> streamOf = Stream.of("apple", "banana", "cherry");

Stream的中间操作

中间操作接收一个Stream,返回一个新的Stream。

  • filter(Predicate<T> predicate): 过滤。保留使predicate返回true的元素。

    1
    2
    // 筛选出长度大于5的字符串
    stream.filter(s -> s.length() > 5);
  • map(Function<T, R> mapper): 映射/转换。将每个元素T转换为一个新的元素R。

    1
    2
    // 将字符串列表转换为其长度的列表
    stream.map(String::length); // 返回一个 Stream<Integer>
  • peek(Consumer<T> action): 主要用于调试,它会对流中的每个元素执行一个操作,但不会改变流本身。

    1
    stream.peek(s -> System.out.println("Processing: " + s));
  • sorted() / sorted(Comparator<T> comparator): 排序。

  • limit(long maxSize): 截断流,使其元素数量不超过maxSize。

  • distinct(): 去重。基于元素的equals()方法。

Stream的终端操作

终端操作是流水线的终点。它会触发所有惰性中间操作的执行,并产生一个最终结果或副作用(打印到控制台,调用某个服务的API等)。

惰性求值:中间操作不会立即执行。它们只是在流水线上注册了一个待执行的操作。只有当一个终端操作被调用时,整个流水线才会从源头开始,依次执行所有中间操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

Stream<String> stream = names.stream()
.filter(name -> {
System.out.println("Filtering: " + name);
return name.length() > 4;
})
.map(name -> {
System.out.println("Mapping: " + name);
return name.toUpperCase();
});

// 直到下面这行终端操作被调用,上面的打印语句才会执行
String firstResult = stream.findFirst().get();
System.out.println("First result: " + firstResult);

消费与副作用:对每个元素执行操作

  • void forEach(Consumer<? super T> action)
    1
    2
    3
    4
    5
    List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
    names.stream()
    .filter(s -> s.startsWith("A"))
    .forEach(System.out::println); // 副作用:打印到控制台
    // 输出: Alice

查询与匹配:检查元素属性

  • Optional<T> findFirst()
  • Optional<T> findAny()
  • boolean anyMatch(Predicate<? super T> predicate), e.g.
    1
    users.stream().anyMatch(user -> user.isAdmin())
  • boolean allMatch(Predicate<? super T> predicate)

归约:将流合并为单个值

比如,计算总和、求最大值、或将所有字符串连接起来等。

  • long count()
  • Optional<T> max(Comparator<? super T> comparator)
  • Optional<T> reduce(BinaryOperator<T> accumulator)
    1
    2
    3
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b); // or Integer::sum
    sum.ifPresent(System.out::println); // 输出: 15

收集:将流元素聚合到容器中

将流中的元素重新组织成另一种形式,通常是一个集合(如List, Set, Map)。语法:<R, A> R collect(Collector<? super T, A, R> collector)

1
Set<String> uniqueNames = names.stream().collect(Collectors.toSet());
  • Collectors.toList()
  • Collectors.toMap()
    1
    2
    3
    4
    5
    Map<String, Integer> nameToAgeMap = people.stream()
    .collect(Collectors.toMap(
    p -> p.getName(), // 获取Key
    p -> p.getAge() // 获取Value
    ));
  • Collectors.joining()
    1
    2
    3
    String names = people.stream()
    .map(Person::getName) // Stream<Person> -> Stream<String>
    .collect(Collectors.joining(", "));
  • Collectors.summingDouble()
    1
    2
    3
    Double totalElectronicsPrice = products.stream()
    .filter(p -> "Electronics".equals(p.getCategory()))
    .collect(Collectors.summingDouble(Product::getPrice));

Optional类

1
2
User user = findUserById("123");
String username = user.getName(); // 如果 user 为 null,这里将抛出 NullPointerException

Optional 的诞生正是为了在类型系统层面解决这个问题。

Definition

java.util.Optional<T> 是一个容器对象,它最多可以持有一个非 null 的 T 类型的值。

创建Optional

  • Optional.of(T value),当你确定 value 绝对不为 null 时使用。如果 value 为 null,它会立即抛出 NullPointerException。

    1
    Optional<String> name = Optional.of("John Doe");
  • Optional.ofNullable(T value),当你持有一个可能为 null 的值时使用。如果 value 不为 null,它会创建一个包含该值的 Optional;如果 value 为 null,它会创建一个空的 Optional。

    1
    Optional<User> user = Optional.ofNullable(findUserFromDB());
  • Optional.ofNullable(T value),如果 value 不为 null,它会创建一个包含该值的 Optional;如果 value 为 null,它会创建一个空的 Optional。

  • Optional.empty(),创建一个空的 Optional 实例。

使用Optional

  • ifPresent(Consumer<? super T> consumer)
    如果你只想在值存在时执行某个操作,可以使用 ifPresent() 方法。
    传统方法:

    1
    2
    3
    4
    String name = getNullableName();
    if (name != null) {
    System.out.println("Name is: " + name);
    }

    使用 ifPresen:

    1
    Optional.ofNullable(getNullableName()).ifPresent(name -> System.out.println("Name is: " + name));
  • orElse(T other) and orElseGet(Supplier<? extends T> other)
    当 Optional 为空时,我们常常需要提供一个默认值。

    1
    2
    String name = Optional.ofNullable(getNullableName()).orElse("default");
    String name2 = Optional.ofNullable(getNullableName()).orElseGet(() -> createDefaultName());
  • Optional 配合 map()

    1
    2
    3
    4
    5
    6
    Optional<User> userOptional = Optional.ofNullable(getUser());
    Optional<String> zipCodeOptional = userOptional
    .map(User::getAddress)
    .map(Address::getZipCode);

    String zipCode = zipCodeOptional.orElse("Not available");

    以上例子中,map(User::getAddress)Optional<User> 转换为了 Optional<Address>,整个过程无需任何 null 检查。

  • Optional 配合 filter()

    1
    2
    3
    4
    5
    6
    Optional<String> name = Optional.of("John Doe");

    // 只有当名字包含 "John" 时才保留
    Optional<String> johnOptional = name.filter(n -> n.contains("John")); // 结果为 Optional["John Doe"]

    Optional<String> janeOptional = name.filter(n -> n.contains("Jane")); // 结果为 Optional.empty

Java基础 - Java函数式编程 - Stream API
https://thiefcat.github.io/2025/08/02/JAVA/java-fp-stream/
Author
小贼猫
Posted on
August 2, 2025
Licensed under