当前位置: 首页 > article >正文

java Stream 详解

Java Stream API 详解

Java Stream API 是 Java 8 引入的一种函数式编程风格的数据处理工具,用于对集合数据进行操作。Stream 提供了一种高效、可读性强的方式来处理数据,支持声明式编程,并利用惰性执行内部迭代来提升性能。


1. 什么是 Stream?

  • Stream 是什么?
    Stream 是对数据集合(如 List、Set、Map)进行处理的抽象层,类似于 SQL 查询中的操作方式。

  • Stream 的特点:

    1. 声明式:通过链式方法调用定义数据操作,代码简洁。
    2. 惰性执行:中间操作不会立即执行,只有在终端操作时才会触发执行。
    3. 无存储:Stream 不存储数据,只是对原始数据的操作视图。
    4. 不可变性:Stream 本身不会改变原始数据。
    5. 易并行:支持并行操作,提高性能。

2. Stream 的工作流程

Stream 的操作通常分为三个部分:

  1. 数据源:通过集合、数组、文件等创建 Stream。
  2. 中间操作:对数据进行过滤、映射、排序等转换,返回新的 Stream。
  3. 终端操作:触发数据流处理并生成结果,如收集、遍历或统计。

3. 创建 Stream

3.1 从集合

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = list.stream();  // 顺序流
Stream<Integer> parallelStream = list.parallelStream(); // 并行流

3.2 从数组

String[] array = {"a", "b", "c"};
Stream<String> stream = Arrays.stream(array);

3.3 使用静态方法

Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);

3.4 创建无限流

// 生成无限流,元素为常量
Stream<Integer> stream = Stream.generate(() -> 1);

// 生成无限流,元素为递增序列
Stream<Integer> stream = Stream.iterate(0, n -> n + 2);

4. 中间操作

中间操作是对 Stream 进行的转换操作,不会触发数据处理,而是返回一个新的 Stream。

4.1 过滤操作

  • filter:筛选符合条件的元素。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> filteredStream = list.stream().filter(n -> n % 2 == 0);

4.2 映射操作

  • map:将每个元素转换为另一个形式。
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> upperStream = list.stream().map(String::toUpperCase);
  • flatMap:将多个流合并为一个流。
List<List<Integer>> lists = Arrays.asList(Arrays.asList(1, 2), Arrays.asList(3, 4));
Stream<Integer> flatStream = lists.stream().flatMap(Collection::stream);

4.3 排序

  • sorted:对流中的元素进行排序。
List<Integer> list = Arrays.asList(5, 1, 4, 2);
Stream<Integer> sortedStream = list.stream().sorted();
Stream<Integer> customSortedStream = list.stream().sorted((a, b) -> b - a); // 自定义排序

4.4 去重

  • distinct:去除重复元素。
List<Integer> list = Arrays.asList(1, 2, 2, 3, 3);
Stream<Integer> distinctStream = list.stream().distinct();

4.5 截取与跳过

  • limit(n):获取前 n 个元素。
  • skip(n):跳过前 n 个元素。
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> limitedStream = list.stream().limit(3); // 1, 2, 3
Stream<Integer> skippedStream = list.stream().skip(2); // 3, 4, 5

5. 终端操作

终端操作会触发 Stream 的实际处理并返回结果。

5.1 收集

  • collect:将 Stream 的元素收集到集合、数组等。
List<String> list = Stream.of("a", "b", "c").collect(Collectors.toList());
Set<String> set = Stream.of("a", "b", "c").collect(Collectors.toSet());

5.2 匹配

  • allMatch:是否所有元素都满足条件。
  • anyMatch:是否存在任意元素满足条件。
  • noneMatch:是否所有元素都不满足条件。
List<Integer> list = Arrays.asList(1, 2, 3, 4);
boolean allEven = list.stream().allMatch(n -> n % 2 == 0); // false
boolean anyEven = list.stream().anyMatch(n -> n % 2 == 0); // true

5.3 查找

  • findFirst:返回第一个元素。
  • findAny:返回任意一个元素。
Optional<Integer> first = Stream.of(1, 2, 3).findFirst();
Optional<Integer> any = Stream.of(1, 2, 3).findAny();

5.4 迭代

  • forEach:遍历元素。
Stream.of("a", "b", "c").forEach(System.out::println);

5.5 统计

  • count:统计元素数量。
  • max / min:获取最大值或最小值。
  • reduce:聚合操作。
long count = Stream.of(1, 2, 3).count();
Optional<Integer> max = Stream.of(1, 2, 3).max(Integer::compareTo);
int sum = Stream.of(1, 2, 3).reduce(0, Integer::sum); // 累加

6. 并行流

通过 parallelStreamparallel() 可以将流转换为并行流,利用多线程处理数据。

使用并行流

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.parallelStream().forEach(n -> {
    System.out.println(Thread.currentThread().getName() + " processes " + n);
});

并行流的注意事项

  1. 线程安全:需保证数据源和终端操作是线程安全的。
  2. 性能评估:并行流适合大数据量操作,小数据量可能会因线程切换损耗性能。

7. Stream 的优点

  1. 简洁:通过链式调用使代码更加简洁易读。
  2. 高效:惰性执行减少不必要的计算。
  3. 并行性:内置并行处理支持,充分利用多核 CPU。
  4. 灵活性:支持多种数据转换和操作。

8. 常见问题与注意事项

  1. Stream 只能使用一次
    流一旦被终端操作消费,就无法再次使用。

    Stream<Integer> stream = Stream.of(1, 2, 3);
    stream.forEach(System.out::println);
    stream.forEach(System.out::println); // 报错
    
  2. Stream 不会修改原数据
    Stream 的操作是惰性执行的,不会直接修改数据源。

  3. 避免过多中间操作
    中间操作过多可能导致性能下降,应合理设计流的处理链。


9. 总结

  • Stream 的核心功能:通过中间操作和终端操作,简化集合数据的处理。
  • 适用场景:适合对集合数据进行过滤、转换、排序、统计等操作。
  • 并行流:充分利用多线程提升性能,但需注意线程安全性。

通过 Stream,可以更优雅地操作数据,提高代码的可读性和开发效率,是现代 Java 编程的重要工具之一。


http://www.kler.cn/a/420414.html

相关文章:

  • 从被动响应到主动帮助,ProActive Agent开启人机交互新篇章
  • 【ONE·基础算法 || 动态规划(三)】
  • apache中的Worker 和 Prefork 之间的区别是什么?
  • 【人工智能】Python与强化学习:从零实现多臂老虎机(Multi-Armed Bandit)问题
  • 107.【C语言】数据结构之二叉树求总节点和第K层节点的个数
  • Linux网络编程之---多线程实现并发服务器
  • 嵌入式Linux无窗口系统下搭建 Qt 开发环境
  • redis针对hash的命令 及 使用场景
  • 电机驱动MCU介绍
  • 理解 Python PIL库中的 convert(‘RGB‘) 方法:为何及如何将图像转换为RGB模式
  • 广东省计算机学会40周年暨2024年庆典活动 粤港澳数字人的生产与驱动技术论坛、第五届人工智能与信息系统国际学术会议
  • 【大数据学习 | 面经】Spark为什么比MR计算更快
  • 解析生成对抗网络(GAN):原理与应用
  • Linux C/C++编程之静态库
  • C语言——宏、预处理、多文件
  • 【WRF-Urban】WPS中有关Urban的变量设置
  • 【大语言模型】ACL2024论文-23 检索增强的多语言知识编辑
  • 按列数据拆分到工作表-Excel易用宝
  • 【HM-React】02. React基础-下
  • CC++ 标准库与标准模板库(STL)简介
  • Flink学习连载文章9--状态(State)
  • 群控系统服务端开发模式-应用开发-邮箱短信通道功能开发
  • 65页PDF | 企业IT信息化战略规划(限免下载)
  • idea中git的将A分支某次提交记录合并到B分支
  • 大模型缩放法则放缓,OpenAI、谷歌、Anthropic推进AI模型创新 | LeetTalk Daily
  • 大数据新视界 -- 大数据大厂之 Hive 数据压缩算法对比与选择(下)(20 / 30)