Java Stream API详细用法

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

🚀 一、什么是 Stream(流)

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

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

示例:

plain 复制代码
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️⃣ 创建流

常见的几种方式:

plain 复制代码
// 从集合创建
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)

示例:

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

示例:

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

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

🧩 三、收集器(Collectors)

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

🔹 转换为集合

plain 复制代码
.collect(Collectors.toList());
.collect(Collectors.toSet());
.collect(Collectors.toMap(User::getId, User::getName));

🔹 分组

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

🔹 多级分组

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

🔹 聚合统计

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

🔹 拼接字符串

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

输出示例:

plain 复制代码
[张三, 李四, 王五]

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

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

示例:

plain 复制代码
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(),即可让处理自动并行,提高性能(适合大数据量场景):

plain 复制代码
long count = list.parallelStream()
    .filter(x -> x > 100)
    .count();

⚠️ 注意:

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

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

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

🧾 七、常见高级技巧

✅ 去重(按字段)

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

✅ 统计字段总和

plain 复制代码
int totalAge = users.stream()
    .mapToInt(User::getAge)
    .sum();

✅ 分页(Stream 模拟分页)

plain 复制代码
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() 分组与聚合
相关推荐
蒜香拿铁2 小时前
【第五章】python判断语句if
java·服务器·python
毕设源码-朱学姐2 小时前
【开题答辩全过程】以 公寓楼设备报修管理系统为例,包含答辩的问题和答案
java·eclipse
qq_12498707532 小时前
基于微信小程序的宠物寄领养系统(源码+论文+部署+安装)
java·spring boot·后端·微信小程序·小程序·宠物·计算机毕业设计
Yeats_Liao2 小时前
显存瓶颈分析:大模型推理过程中的内存管理机制
python·深度学习·神经网络·架构·开源
独自破碎E2 小时前
说说Java中的JIT
java·开发语言
齐鲁大虾2 小时前
如何通过Java调取打印机打印图片和文本
java·开发语言·python
carver w2 小时前
张氏相机标定,不求甚解使用篇
c++·python·数码相机
No0d1es2 小时前
2025年第十六届蓝桥杯青少组省赛 Python编程 初/中级组真题
python·蓝桥杯·第十六届·省事
Sator12 小时前
Unity的InputSystem常见问题和疑惑解答
java·unity·游戏引擎