Java Stream API详细用法

67 阅读3分钟

Java Stream API(流式编程接口)是在 Java 8 引入的,用于对集合(Collection)或数组进行高效、简洁、并行的操作。


🚀 一、什么是 Stream(流)

Stream 不是集合,它是一种 对数据进行操作的“视图”
可以理解为一条“数据流水线”:

  • 数据来源:集合、数组、文件、IO等;
  • 中间操作:过滤、排序、映射、分组;
  • 终止操作:收集、计数、求和、遍历。

示例:

List<String> names = List.of("张三", "李四", "王五", "张三丰");

List<String> result = names.stream()
        .filter(name -> name.startsWith("张")) // 过滤姓张
        .distinct()                           // 去重
        .sorted()                             // 排序
        .collect(Collectors.toList());        // 收集为列表

System.out.println(result); // 输出: [张三, 张三丰]

🧱 二、Stream 的基本结构

1️⃣ 创建流

常见的几种方式:

// 从集合创建
Stream<String> s1 = list.stream();

// 从数组创建
Stream<Integer> s2 = Arrays.stream(new Integer[]{1, 2, 3});

// 直接创建
Stream<String> s3 = Stream.of("A", "B", "C");

// 无限流(常用于测试或算法)
Stream<Integer> s4 = Stream.iterate(0, n -> n + 2).limit(5); // 0,2,4,6,8

2️⃣ 中间操作(Intermediate Operations)

这些操作会返回一个新的 Stream,不会立即执行,直到终止操作发生时才会触发。

方法功能示例
filter(Predicate)过滤.filter(x -> x > 5)
map(Function)转换元素.map(x -> x * 2)
flatMap(Function)扁平化嵌套流.flatMap(list -> list.stream())
distinct()去重.distinct()
sorted()排序.sorted().sorted(Comparator)
limit(n)取前 n 个.limit(5)
skip(n)跳过前 n 个.skip(3)
peek(Consumer)调试查看.peek(System.out::println)

示例:

List<Integer> nums = List.of(1, 2, 3, 4, 5, 6);
nums.stream()
    .filter(n -> n % 2 == 0)   // 过滤偶数
    .map(n -> n * n)           // 平方
    .forEach(System.out::println); // 输出: 4, 16, 36

3️⃣ 终止操作(Terminal Operations)

这些方法会触发实际执行,返回结果或执行动作。

方法功能示例
forEach(Consumer)遍历.forEach(System.out::println)
collect(Collector)收集结果.collect(Collectors.toList())
count()计数.count()
findFirst()找第一个.findFirst().orElse(null)
findAny()找任意一个(并行流).findAny()
anyMatch(Predicate)存在匹配.anyMatch(x -> x > 10)
allMatch(Predicate)全部匹配.allMatch(x -> x > 0)
noneMatch(Predicate)全部不匹配.noneMatch(x -> x < 0)
max(Comparator)最大值.max(Integer::compare)
min(Comparator)最小值.min(Integer::compare)
reduce()累加、归约.reduce(0, (a,b)->a+b)

示例:

int sum = List.of(1, 2, 3, 4, 5)
        .stream()
        .reduce(0, Integer::sum); // 求和

System.out.println(sum); // 15

🧩 三、收集器(Collectors)

Collectors 是 Stream 最强大的工具之一,用于把流的结果转成各种形式:

🔹 转换为集合

.collect(Collectors.toList());
.collect(Collectors.toSet());
.collect(Collectors.toMap(User::getId, User::getName));

🔹 分组

Map<String, List<User>> byDept = users.stream()
    .collect(Collectors.groupingBy(User::getDeptName));

🔹 多级分组

Map<String, Map<String, List<User>>> multiGroup = users.stream()
    .collect(Collectors.groupingBy(User::getDeptName,
             Collectors.groupingBy(User::getGender)));

🔹 聚合统计

Double avg = users.stream()
    .collect(Collectors.averagingInt(User::getAge)); // 平均年龄

🔹 拼接字符串

String names = users.stream()
    .map(User::getName)
    .collect(Collectors.joining(", ", "[", "]"));

输出示例:

[张三, 李四, 王五]

⚡ 四、flatMap 扁平化(常见难点)

flatMap()嵌套集合 展开成一个扁平的流。

示例:

List<List<String>> nested = List.of(
    List.of("A", "B"),
    List.of("C", "D")
);

List<String> flat = nested.stream()
    .flatMap(Collection::stream)
    .collect(Collectors.toList());

System.out.println(flat); // [A, B, C, D]

🧠 五、并行流(Parallel Stream)

只需 .parallelStream(),即可让处理自动并行,提高性能(适合大数据量场景):

long count = list.parallelStream()
    .filter(x -> x > 100)
    .count();

⚠️ 注意:

  • 并行流开销较大,不适合小集合;
  • 注意线程安全,尤其是写共享变量时。

🛠️ 六、自定义排序与过滤

List<User> sorted = users.stream()
    .filter(u -> u.getAge() > 18)
    .sorted(Comparator.comparing(User::getAge).reversed())
    .collect(Collectors.toList());

🧾 七、常见高级技巧

✅ 去重(按字段)

List<User> unique = users.stream()
    .filter(distinctByKey(User::getId))
    .collect(Collectors.toList());

public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(keyExtractor.apply(t));
}

✅ 统计字段总和

int totalAge = users.stream()
    .mapToInt(User::getAge)
    .sum();

✅ 分页(Stream 模拟分页)

List<User> pageList = users.stream()
    .skip((pageNum - 1) * pageSize)
    .limit(pageSize)
    .collect(Collectors.toList());

✅ 八、总结口诀

阶段方法示例说明
创建流stream() / of()创建流对象
中间操作filter()、map()、sorted()不会立即执行
终止操作collect()、count()、forEach()触发执行
收集器Collectors.toList()转换为集合
常用高级groupingBy()、joining()分组与聚合