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

Java Stream 初解

目录

一、什么是 Stream?

二、Stream 的核心特性

三、Stream 流水线

1. 源 (Source)

2. 中间操作 (Intermediate Operations)

3. 终端操作 (Terminal Operation)

四、常用 Stream 操作

1. 过滤与映射

2.归约操作

3.并行流


一、什么是 Stream?

Stream(流)Java 8 中引入的一个全新概念,它代表支持顺序和并行聚合操作的元素序列。与集合 (Collection) 不同:

  • 集合关注元素的存储和访问
  • Stream 关注元素的计算和处理

Stream 本身并不存储元素,它更像一个高级迭代器,能够以声明式方式描述对数据源的一系列操作。

// 一个简单的Stream示例
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
long count = names.stream().filter(name -> name.length() > 4)  // 过滤出长度大于4的名字.count();  // 计数
System.out.println(count);  // 输出:2("Alice"和"Charlie")

二、Stream 的核心特性

惰性求值:中间操作不会立即执行,只有当终端操作被调用时,所有中间操作才会一次性执行("延迟执行")。

流水线操作:Stream 操作可以串联成一个流水线(pipeline),形成清晰的操作链。

一次性使用:一个 Stream 只能被操作一次,再次使用会抛出IllegalStateException

支持并行:无需额外代码,即可轻松实现并行处理(利用多线程)。

无存储:Stream 不存储元素,元素只在需要时才被计算。

三、Stream 流水线

一个完整的 Stream 操作由三部分组成:

源 (Source)→中间操作 (Intermediate Operations)→终端操作 (Terminal Operation)

1. 源 (Source)

Stream 的数据源可以是:

  • 集合(collection.stream()collection.parallelStream()
  • 数组(Arrays.stream(array)
  • 生成器函数(Stream.generate()
  • I/O 通道(如Files.lines(Path)
// 从集合创建
List<Integer> list = Arrays.asList(1, 2, 3);
Stream<Integer> streamFromList = list.stream();// 从数组创建
int[] array = {1, 2, 3};
IntStream streamFromArray = Arrays.stream(array);// 从生成器创建(无限流)
Stream<Double> randomStream = Stream.generate(Math::random);

2. 中间操作 (Intermediate Operations)

中间操作用于转换 Stream,返回一个新的 Stream。常见的中间操作包括

操作描述
filter(Predicate)过滤出满足条件的元素
map(Function)对元素执行映射转换
flatMap(Function)将元素转换为 Stream 并扁平化
distinct()去重(基于equals()
sorted()排序(自然顺序或指定比较器)
limit(long)截断流,保留前 n 个元素
skip(long)跳过前 n 个元素
List<String> words = Arrays.asList("apple", "banana", "cherry", "date");Stream<String> processedStream = words.stream().filter(word -> word.length() > 5)  // 保留长度>5的单词.map(String::toUpperCase)  // 转换为大写.distinct()  // 去重(这里示例中无重复,仅作演示).sorted();  // 排序

3. 终端操作 (Terminal Operation)

终端操作会触发整个流水线的执行,并产生一个结果或副作用。执行后,Stream 将不可再用

常见的终端操作包括:

操作描述
forEach(Consumer)遍历元素执行操作
count()返回元素数量
collect(Collector)收集元素到集合或其他结构
reduce(BinaryOperator)归约操作,产生单个结果
min(Comparator)/max(Comparator)查找最小 / 最大值
anyMatch(Predicate)/allMatch(Predicate)/noneMatch(Predicate)匹配检查
findFirst()/findAny()查找元素
List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");// 1. 收集到List
List<String> longFruits = fruits.stream().filter(f -> f.length() > 5).collect(Collectors.toList());// 2. 归约求和(字符串长度总和)
int totalLength = fruits.stream().mapToInt(String::length).sum();// 3. 匹配检查
boolean hasShortFruit = fruits.stream().anyMatch(f -> f.length() <= 4);  // "date"长度为4,返回true

四、常用 Stream 操作

1. 过滤与映射

这是最常用的组合操作,先过滤出需要的元素,再进行转换处理。

// 示例:找出所有偶数并计算它们的平方和
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int sumOfEvenSquares = numbers.stream().filter(n -> n % 2 == 0)  // 过滤偶数.mapToInt(n -> n * n)     // 计算平方.sum();                   // 求和System.out.println(sumOfEvenSquares);  // 输出:220(2²+4²+6²+8²+10²)

2.归约操作

reduce()用于将 Stream 中的元素通过累加器组合成一个结果。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);// 1. 计算总和(有初始值)
int sumWithIdentity = numbers.stream().reduce(0, Integer::sum);  // 0为初始值,累加所有元素// 2. 计算最大值(无初始值,返回Optional)
Optional<Integer> max = numbers.stream().reduce(Integer::max);// 3. 拼接字符串
List<String> words = Arrays.asList("Hello", " ", "World", "!");
String sentence = words.stream().reduce("", String::concat);  // 结果:"Hello World!"

3.并行流

Stream API 最强大的特性之一是对并行处理的支持。只需将stream()改为parallelStream(),即可实现并行操作。

// 并行计算1到1000000的总和
long sum = IntStream.rangeClosed(1, 1000000).parallel()  // 转为并行流.sum();System.out.println(sum);  // 输出:500000500000

注意:并行流使用公共的 ForkJoinPool,适用于 CPU 密集型任务。对于 IO 密集型任务,效果可能不佳甚至更差。

并行流就像一个公共的 "多人工厂",适合干 "费脑子但不费时间等" 的活,不适合干 "大部分时间在等" 的活。

具体来说:

1.  CPU 密集型任务:比如复杂计算、数据处理等,这些任务主要靠 CPU"使劲算",几乎不需要等待。

  • 这时候用并行流(多线程)能明显提高效率,就像多个人同时埋头算账,肯定比一个人算得快。

2.  IO 密集型任务:比如网络请求、文件读写等,这些任务大部分时间都在 "等待"(等数据传输、等磁盘响应)。

  • 这时候用并行流效果不好,因为就算开多个线程,大部分时间还是在等,多线程的优势发挥不出来,反而会因为线程切换增加额外开销,就像多个人一起等快递,并不会比一个人等来得更快。

举个生活例子:

  • 算 100 道数学题(CPU 密集):5 个人同时算比 1 个人算快很多
  • 打 100 个电话(IO 密集,大部分时间在等对方接):5 个人打并不比 1 个人打快多少,反而可能因为协调问题更麻烦
http://www.dtcms.com/a/335946.html

相关文章:

  • 14.web api 5
  • 基于MATLAB多智能体强化学习的出租车资源配置优化系统设计与实现
  • 无人机视角乱堆垃圾垃圾场地分割数据集labelme格式1501张1类别
  • qt svg缺失元素, 原因是不支持 rgba
  • Android studio gradle有关设置
  • 图解 setTimeout + 循环:var 共享变量 vs let 独立绑定
  • 《若依》介绍和环境搭建
  • 基于径向基函数神经网络的数据回归预测 RBF
  • 2024年08月13日 Go生态洞察:Go 1.23 发布与全面深度解读
  • 三维重建-动手学计算机视觉19(完结)
  • Android Studio中创建Git分支
  • ——分治——
  • metasploit 框架安装更新遇到无法下载问题如何解决
  • Sentinel和12.5米高程的QGIS 3D效果
  • 双椒派E2000D Sysfs与GPIO控制实战指南
  • KINGBASE集群日常维护管理命令总结
  • 云原生俱乐部-杂谈3
  • 深入掌握 Kubernetes Deployment:部署、重启、管理和维护全攻略
  • 为什么TCP连接是三次握手?不是四次两次?
  • 《Cocos游戏开发入门一本通》第四章
  • 智能体的记忆(Memory)系统
  • HAL-USART配置
  • 数据处理到底能做什么?数据处理核心原理与流程拆解
  • Web 开发 16
  • uniapp打包安卓app
  • k8s集群搭建一主多从的jenkins集群
  • 今日科技热点速递:机遇与技术融合下的创新加速
  • React学习(三)
  • ubuntu常见问题汇总
  • 猫头虎AI分享|一款Coze、Dify类开源AI应用超级智能体快速构建工具:FastbuildAI