Stream 是 Java 8 引入的一个非常强大的 API,它可以用来处理集合(如 List、Set 等)中的数据。Stream 提供了一种声明式的方式来处理集合的数据流,可以让你以更简洁、易读的方式编写代码。

1. 创建 Stream

可以通过以下几种方式创建一个 Stream:

  • 从集合创建:可以直接从集合(如 List、Set)中获取 Stream。
List<String> list = Arrays.asList("a", "b", "c", "d");
Stream<String> stream = list.stream();
  • 通过 Arrays 类创建:使用 Arrays.stream() 可以将数组转换成 Stream。
String[] array = {"a", "b", "c", "d"};
Stream<String> stream = Arrays.stream(array);
  • 通过 Stream.of():通过 Stream.of() 创建包含一个或多个元素的流。
Stream<String> stream = Stream.of("a", "b", "c");

2. 常用操作

Stream 操作分为两类:中间操作终端操作

中间操作

中间操作是延迟计算的,它返回一个新的 Stream,因此可以链式调用。

  • filter:根据给定的条件过滤元素。
Stream<String> filtered = stream.filter(s -> s.startsWith("a"));
  • map:将元素应用于函数,转换成另一个类型或值。
Stream<String> mapped = stream.map(String::toUpperCase);
  • distinct:去除重复元素。
Stream<String> distinct = stream.distinct();
  • sorted:对元素进行排序。
Stream<String> sorted = stream.sorted();
  • limit:限制流的元素个数。
Stream<String> limited = stream.limit(2);  // 获取前两个元素
  • skip:跳过指定数量的元素。
Stream<String> skipped = stream.skip(1);  // 跳过第一个元素

终端操作

终端操作会触发流的计算,并且会消耗流。每个流只能执行一次终端操作。

  • forEach:遍历流中的每个元素。
stream.forEach(System.out::println);
  • collect:将流的元素收集到一个集合中。
List<String> list = stream.collect(Collectors.toList());
Set<String> set = stream.collect(Collectors.toSet());
  • reduce:通过一个结合操作将流中的元素合并成一个单一的值。
Optional<String> result = stream.reduce((s1, s2) -> s1 + s2);
  • count:返回流中元素的个数。
long count = stream.count();
  • anyMatchallMatchnoneMatch:检查流中的元素是否符合某些条件。
boolean result = stream.anyMatch(s -> s.startsWith("a"));
  • findFirst:返回流中的第一个元素。
Optional<String> first = stream.findFirst();
  • findAny:返回流中的任意一个元素。
Optional<String> any = stream.findAny();

3. 示例

import java.util.*;
import java.util.stream.*;

public class StreamExample {
    public static void main(String[] args) {
        // 创建一个List
        List<String> list = Arrays.asList("apple", "banana", "cherry", "date", "fig", "grape");

        // 使用Stream进行处理
        list.stream()
            .filter(s -> s.startsWith("a"))  // 过滤出以"a"开头的元素
            .map(String::toUpperCase)        // 将元素转换为大写
            .sorted()                        // 对元素进行排序
            .forEach(System.out::println);   // 输出结果
    }
}

输出:

APPLE

4. 注意事项

  • Stream 不可重复使用:Stream 一旦被消耗(例如执行了 forEach 或其他终端操作),它就不能再被使用。如果需要重复使用,需要重新创建 Stream。
  • 懒加载:Stream 中的中间操作是懒加载的,只有在终端操作触发时才会开始执行。