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

Java 8 Stream 介绍

Java 8 Stream 介绍

1. 什么是Stream?

Stream(流)是Java 8引入的全新概念,它是一个支持串行和并行聚合操作的元素序列。Stream API提供了一种声明式的方式来处理数据集合,可以让我们以一种类似SQL查询的方式处理数据。

Stream的特点:

  1. 声明式处理:通过声明要做什么,而不是如何做
  2. 链式操作:支持多个操作的链式调用
  3. 惰性计算:中间操作不会立即执行
  4. 可并行:易于转换为并行操作
  5. 一次性使用:Stream只能被消费一次

2. Stream的基本用法

1. 创建Stream

// 1. 从Collection创建
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream1 = list.stream();// 2. 从数组创建
String[] array = {"a", "b", "c"};
Stream<String> stream2 = Arrays.stream(array);// 3. 使用Stream.of()
Stream<String> stream3 = Stream.of("a", "b", "c");// 4. 创建数值流
IntStream intStream = IntStream.range(1, 5); // 1,2,3,4
DoubleStream doubleStream = DoubleStream.of(1.1, 2.2, 3.3);// 5. 创建无限流
Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 2); // 偶数流
Stream<Double> randomStream = Stream.generate(Math::random);    // 随机数流

2. Stream操作的类型

Stream API的操作可以分为两类:

2.1 中间操作(Intermediate Operations)
  • 返回新的Stream
  • 是惰性的(lazy)
  • 不会立即执行
// 常见的中间操作
Stream<String> stream = list.stream().filter(s -> s.length() > 3)    // 过滤.map(String::toUpperCase)       // 转换.distinct()                     // 去重.sorted()                       // 排序.limit(5);                      // 限制数量
2.2 终端操作(Terminal Operations)
  • 产生结果
  • 会触发实际计算
  • 执行后Stream不能再被使用
// 常见的终端操作
long count = stream.count();                    // 计数
List<String> result = stream.collect(Collectors.toList());  // 收集到List
String joined = stream.collect(Collectors.joining(", "));   // 连接字符串

3. Stream的常用操作示例

1. 过滤和映射

List<String> names = Arrays.asList("John", "Jane", "Adam", "Tom");// 过滤以'J'开头的名字并转换为大写
List<String> filteredNames = names.stream().filter(name -> name.startsWith("J")).map(String::toUpperCase).collect(Collectors.toList());
// 结果: [JOHN, JANE]// map:一对一映射
List<String> words = Arrays.asList("hello", "world");
List<Integer> wordLengths = words.stream().map(String::length).collect(Collectors.toList());  // [5, 5]// flatMap:一对多映射
List<List<Integer>> nestedNumbers = Arrays.asList(Arrays.asList(1, 2, 3),Arrays.asList(4, 5, 6)
);
List<Integer> flattenedNumbers = nestedNumbers.stream().flatMap(Collection::stream).collect(Collectors.toList());  // [1, 2, 3, 4, 5, 6]

2. 排序和限制

/ 自然排序
List<Integer> sorted = numbers.stream().sorted().collect(Collectors.toList());// 自定义排序
List<String> names = Arrays.asList("John", "Jane", "Adam");
List<String> sortedByLength = names.stream().sorted(Comparator.comparing(String::length)).collect(Collectors.toList());// 反向排序
List<Integer> reverseSorted = numbers.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());// 获取前3个最大的数字
List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6, 5);List<Integer> top3 = numbers.stream().sorted(Comparator.reverseOrder()).distinct().limit(3).collect(Collectors.toList());
// 结果: [9, 6, 5]

3. 统计和汇总

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);// 基本统计
IntSummaryStatistics stats = numbers.stream().mapToInt(Integer::intValue).summaryStatistics();System.out.println("Average: " + stats.getAverage());  // 3.0
System.out.println("Sum: " + stats.getSum());         // 15
System.out.println("Max: " + stats.getMax());         // 5
System.out.println("Min: " + stats.getMin());        // 1

4. 分组和分区

List<Person> people = Arrays.asList(new Person("John", 25),new Person("Jane", 30),new Person("Adam", 25)
);// 按年龄分组
Map<Integer, List<Person>> byAge = people.stream().collect(Collectors.groupingBy(Person::getAge));// 按年龄是否大于27分区
Map<Boolean, List<Person>> partitioned = people.stream().collect(Collectors.partitioningBy(p -> p.getAge() > 27));

5. 收集结果

// 收集为List
List<Integer> list = numbers.stream().collect(Collectors.toList());// 收集为Set
Set<Integer> set = numbers.stream().collect(Collectors.toSet());// 收集为Map
Map<String, Integer> map = names.stream().collect(Collectors.toMap(Function.identity(),    // 键映射函数String::length         // 值映射函数));// 连接字符串
String joined = names.stream().collect(Collectors.joining(", "));

3.2 规约操作

// reduce:求和
int sum = numbers.stream().reduce(0, Integer::sum);// reduce:求最大值
Optional<Integer> max = numbers.stream().reduce(Integer::max);// reduce:字符串连接
String concatenated = words.stream().reduce("", String::concat);

3.4 匹配操作

// anyMatch:是否存在匹配元素
boolean hasEven = numbers.stream().anyMatch(n -> n % 2 == 0);// allMatch:是否所有元素都匹配
boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);// noneMatch:是否没有匹配元素
boolean noneNegative = numbers.stream().noneMatch(n -> n < 0);

4. 并行流操作

4.1 创建并行流

// 从集合创建并行流
List<Integer> parallelResult = numbers.parallelStream().map(n -> n * 2).collect(Collectors.toList());// 将顺序流转换为并行流
List<Integer> parallelResult2 = numbers.stream().parallel().map(n -> n * 2).collect(Collectors.toList());

4.2 并行流注意事项

// 使用forEachOrdered保证顺序
numbers.parallelStream().forEachOrdered(System.out::println);// 使用线程安全的收集器
List<Integer> syncList = numbers.parallelStream().collect(Collectors.toCollection(CopyOnWriteArrayList::new));## Stream使用的注意事项1. **Stream不存储数据**- Stream不是数据结构- Stream只是用于计算的抽象2. **Stream操作是惰性的**- 中间操作不会立即执行- 只有遇到终端操作时才会执行3. **Stream不能重复使用**
```java
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
// 下面的代码会抛出异常
stream.forEach(System.out::println); // IllegalStateException
  1. 注意空指针
// 推荐使用Optional避免空指针
Optional<String> first = stream.filter(s -> s.length() > 3).findFirst();
  1. 合理使用并行流
// 数据量大时使用并行流可提高性能
List<Integer> result = numbers.parallelStream().filter(n -> n > 100).collect(Collectors.toList());

5. 实际应用示例

5.1 数据过滤和转换

class Person {String name;int age;String city;// 构造函数和getter/setter省略
}List<Person> people = // 假设这里有一个Person列表// 获取所有成年人的姓名,按字母排序
List<String> adultNames = people.stream().filter(p -> p.getAge() >= 18).map(Person::getName).sorted().collect(Collectors.toList());// 按城市对人进行分组
Map<String, List<Person>> peopleByCity = people.stream().collect(Collectors.groupingBy(Person::getCity));

5.2 复杂数据处理

// 计算每个城市的平均年龄
Map<String, Double> avgAgeByCity = people.stream().collect(Collectors.groupingBy(Person::getCity,Collectors.averagingInt(Person::getAge)));// 找出每个城市年龄最大的人
Map<String, Optional<Person>> oldestByCity = people.stream().collect(Collectors.groupingBy(Person::getCity,Collectors.maxBy(Comparator.comparing(Person::getAge))));

6. 最佳实践

  1. 使用Stream的时机

    • 当需要对集合进行复杂操作时
    • 当操作可以被链式调用表示时
    • 当需要并行处理数据时
  2. 性能考虑

    • 避免过度使用Stream
    • 注意中间操作的顺序(例如,先filter后map通常更高效)
    • 大数据量时考虑使用并行流
  3. 代码可读性

    • 适当换行以提高可读性
    • 使用有意义的变量名
    • 复杂操作添加适当的注释
  4. 调试技巧

    • 使用peek()方法调试中间结果
    • 合理拆分复杂的Stream操作链
    • 使用适当的日志记录

7. 常见问题和解决方案

  1. 无限流的处理
// 错误示例
Stream.iterate(0, n -> n + 1); // 无限流// 正确示例
Stream.iterate(0, n -> n + 1).limit(10); // 限制元素数量
  1. 并行流的线程安全
// 错误示例
List<String> result = new ArrayList<>();
stream.parallel().forEach(result::add); // 线程不安全// 正确示例
List<String> result = stream.parallel().collect(Collectors.toList()); // 使用线程安全的收集器
  1. Stream重复使用
// 错误示例
Stream<String> stream = list.stream();
stream.forEach(System.out::println);
stream.forEach(System.out::println); // 抛出异常// 正确示例
list.stream().forEach(System.out::println);
list.stream().forEach(System.out::println); // 每次创建新的Stream

8. Stream的优势

  1. 代码简洁

    • 使用Stream可以用更少的代码完成复杂的数据处理
  2. 提高可读性

    • 声明式的处理方式更容易理解代码意图
  3. 支持并行

    • 轻松实现并行处理,提高性能
  4. 延迟执行

    • 惰性计算提高了程序效率

9. 实际应用场景

  1. 数据过滤和转换
// 过滤和转换用户数据
List<UserDTO> userDTOs = users.stream().filter(user -> user.isActive()).map(user -> convertToDTO(user)).collect(Collectors.toList());
  1. 数据统计分析
// 计算订单总金额
double totalAmount = orders.stream().mapToDouble(Order::getAmount).sum();
  1. 复杂数据处理
// 按部门统计员工平均工资
Map<String, Double> avgSalaryByDept = employees.stream().collect(Collectors.groupingBy(Employee::getDepartment,Collectors.averagingDouble(Employee::getSalary)));

相关文章:

Java 8 Stream 介绍

Java 8 Stream 介绍 1. 什么是Stream&#xff1f; Stream&#xff08;流&#xff09;是Java 8引入的全新概念&#xff0c;它是一个支持串行和并行聚合操作的元素序列。Stream API提供了一种声明式的方式来处理数据集合&#xff0c;可以让我们以一种类似SQL查询的方式处理数据…...

Java NIO、AIO分析

好的&#xff0c;下面将对Java中的**NIO&#xff08;Non-blocking IO&#xff09;和AIO&#xff08;Asynchronous IO&#xff09;**进行更深入的分析&#xff0c;重点探讨它们的特点和具体的应用场景。 一、Java NIO&#xff08;Non-blocking IO&#xff09;深入分析 1. 主要…...

pip下载包出现SSLError

报错&#xff1a; ERROR: Could not install packages due to an OSError: HTTPSConnectionPool(host‘files.pythonhosted.org’, port443): Max retries exceeded with url: /packages/8a/c2/ae7227e4b089c6a8210920db9d5ac59186b0a84eb1e6d96b9218916cdaf1/taming_transform…...

零成本的互联网创业创意有哪些?

在互联网时代&#xff0c;创业的门槛大大降低&#xff0c;即使没有大量的资金投入&#xff0c;也有许多机会可以实现创业梦想。以下将为您介绍一些零成本的互联网创业创意&#xff0c;帮助您在互联网的海洋中找到属于自己的宝藏。 一、内容创作与自媒体 &#xff08;一&#…...

linux ubantu重启桌面

在 Ubuntu 系统中&#xff0c;重启桌面环境通常有几种方法&#xff0c;具体取决于你所使用的桌面环境&#xff08;如 GNOME、KDE 等&#xff09;。下面是几种常用的重启桌面的方法&#xff1a; 重启 GNOME 桌面环境 如果你使用的是 GNOME 桌面环境&#xff08;Ubuntu 默认桌面…...

DeepSeek重新定义“Open“AI

“面对颠覆性技术&#xff0c;闭源所创造的护城河是暂时的。即使是OpenAI的闭源方法也无法阻止他人赶超。” ——梁文锋&#xff0c;DeepSeek CEO DeepSeek V3 是一个拥有6710亿参数的开源AI模型&#xff0c;正在提升AI效率的新标准。它在相对有限的预算下进行训练&#xff0c…...

iOS - 自旋锁

在 Objective-C 运行时中大量使用自旋锁&#xff0c;主要有以下几个原因&#xff1a; 1. 性能考虑 上下文切换成本 // 自旋锁实现 static ALWAYS_INLINE void OSSpinLockLock(volatile OSSpinLock *lock) {do {while (lock->value ! 0) {__asm__ volatile ("pause&q…...

web应用网站如何启用http2请求

要启用 HTTP/2 协议&#xff0c;您需要确保您的 Web 服务器软件支持 HTTP/2&#xff0c;并进行相应的配置。以下是一些常见的 Web 服务器软件及其启用 HTTP/2 的方法&#xff1a; 1. Nginx 对于 Nginx&#xff0c;您需要确保使用的是 1.9.5 或更高版本&#xff0c;因为这些版本…...

python进阶06:MySQL

课后大总结 Day1 一、数据库命令总结 1.连接数据库 连接数据库进入mysql安装目录打开bin文件夹&#xff0c;输入cmd(此命令后无分号)mysql.exe -u root -ppassword命令后输入密码:root 设置密码set passwordpassword("root123"); 查看所有数据库show databases; …...

mac 使用zip2john破解zip压缩包密码

一、下载&#xff1a; git clone https://github.com/magnumripper/JohnTheRipper.git cd JohnTheRipper/src ./configure sudo make -s clean && sudo make -sj4 cd ../run二、使用&#xff1a; zip2john提取提取 ZIP 文件的哈希&#xff1a; ./zip2john protecte…...

若依中Feign调用的具体使用(若依微服务版自身已集成openfeign依赖,并在此基础上定义了自己的注解)

若依中Feign调用具体使用 注意&#xff1a;以下所有步骤实现的前提是需要在启动类上加入注解 EnableRyFeignClients 主要是为开启feign接口扫描 1.创建服务提供者(provider) 导入依赖(我在分析依赖时发现若依本身已经引入openfeign依赖,并在此基础上自定义了自己的EnableRyF…...

【算法题系列】LeetCode 5.最长回文子串|JavaScript 5种思路实现

题目描述 给定一个字符串 s&#xff0c;找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 示例 1&#xff1a; 输入: "babad" 输出: "bab" 注意: "aba" 也是一个有效答案。 示例 2&#xff1a; 输入: "cbbd" 输出: &q…...

基于ROS先验地图的机器人自主定位与导航SLAM

2021年学习&#xff0c;当时参加科大讯飞的智能车大赛&#xff0c; 【语音交互启动-teb算法路径规划A*算法自动避障路径最短优化yolo5目标检测视觉结果判断分类终点指定点位自动泊车语音播报。】 【讯飞学院】http://www.iflyros.com/home/ 一、全局路径规划中的地图 栅格地图&…...

nginx 1.6.3配置虚拟主机与rewrite-location匹配规则

1、 Nginx 虚拟主机配置&#xff08;配置文件末尾以分号[&#xff1b;]结尾&#xff09; (1) 准备测试目录站点 [rootWEB conf]# cd /application/nginx/conf/ [rootWEB conf]# mkdir extra &#xff08;创建虚拟主机存放目录&#xff0…...

1130-host ... is not allowed to connect to this MySql serve

局域网内另外一台电脑使用navicat连接Mysql出现上述问题&#xff1a;不允许连接 解决方案&#xff1a; 1、输入命令&#xff1a;进入mysql mysql -u root -p 2、输入命令&#xff1a;展示所有数据库 show databases; 3、输入命令进入mysql数据库&#xff1a; use mysql; 4、…...

力扣1502判断能否形成等差数列

class Solution:def canMakeArithmeticProgression(self, arr: List[int]) -> bool:# 对数组进行排序arr.sort()# 计算公差diff arr[1] - arr[0]# 从第二个元素开始逐个检查差值是否一致for i in range(1, len(arr) - 1):if arr[i 1] - arr[i] ! diff:return Falsereturn …...

Python版本变更历史及版本选择指南

Python版本变更历史及版本选择指南 Python版本变更历史及版本选择指南1. Python 3.13.1&#xff08;2023年发布&#xff09;主要特性适用场景 2. Python 3.12&#xff08;2022年发布&#xff09;主要特性 3. Python 3.11&#xff08;2022年发布&#xff09;主要特性 4. Python …...

初始值变量类型

状态名同步位置初始值变量类型不支持的UL刷新注意事项State父组件必填Object、classstring、number、boolean、enum类型&#xff0c;以及这些类型的数组。支持Date类型。对象的对象数组属性更新数组对象的属性更新 State装饰的变量必须初始化&#xff0c;否则编译期会报错。Sta…...

苍穹外卖 项目记录 day03

文章目录 菜品管理模块开发公共字段填充自定义注解 AutoFill自定义切面 AutoFillAspect在Mapper接口的方法上加入 AutoFill 注解 新增菜品文件上传实现新增菜品实现菜品分页查询删除菜品实现修改菜品实现 菜品管理模块开发 公共字段填充 在新增员工或者新增菜品分类时需要设置…...

统计字符【2】(PTA)C语言

本题要求编写程序&#xff0c;输入N个字符&#xff0c;统计其中英文字母、空格或回车、数字字符和其他字符的个数。 输入格式: 输入在第一行中给出正整数N&#xff0c;第二行输入N个字符&#xff0c;最后一个回车表示输入结束&#xff0c;不算在内。 输出格式: 在一行内按照…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

基于Springboot+Vue的办公管理系统

角色&#xff1a; 管理员、员工 技术&#xff1a; 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能&#xff1a; 该办公管理系统是一个综合性的企业内部管理平台&#xff0c;旨在提升企业运营效率和员工管理水…...

WebRTC从入门到实践 - 零基础教程

WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个支持网页浏览器进行实时语音…...

什么是VR全景技术

VR全景技术&#xff0c;全称为虚拟现实全景技术&#xff0c;是通过计算机图像模拟生成三维空间中的虚拟世界&#xff0c;使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验&#xff0c;结合图文、3D、音视频等多媒体元素…...