`.stream()` 的本质是把你的数据集合(List、Set、数组等)变成一根**“数据流水线”**。
在 Java 8 中,操作流有一个非常标准的**“三部曲”顺序**。理解这个顺序,你就能看懂所有的流式代码。
---
### 1. Stream 流的操作三部曲
#### **第一步:获取流 (Source)**
把静态的集合变成流动的状态。
* `list.stream()`
* `Arrays.stream(array)`
#### **第二步:中间操作 (Intermediate Operations) —— 加工**
这是流水线上的工人。**注意:** 中间操作是“懒”的,只有最后一步执行时,它们才会真正开始工作。
* 你可以连接多个中间操作(就像流水线上有多个工位)。
* 每个操作都会返回一个新的流。
#### **第三步:终端操作 (Terminal Operation) —— 收网**
这是流水线的终点。一旦执行,流就会被关闭,并产生一个结果(如 List、数字、或直接消费掉)。
---
### 2. 常用的“中间操作”顺序(加工顺序)
在实际开发中,我们通常按照以下逻辑顺序来排列方法:
| 推荐顺序 | 方法名 | 作用 | 为什么排在这里? |
| --- | --- | --- | --- |
| **1. 过滤** | **`.filter()`** | 扔掉不需要的数据 | **最优先执行**。数据越少,后面操作越快。 |
| **2. 去重** | **`.distinct()`** | 去掉重复项 | 减少后续不必要的重复计算。 |
| **3. 排序** | **`.sorted()`** | 对数据排序 | 通常在过滤后排序,效率更高。 |
| **4. 转换** | **`.map()`** | 改变数据类型或提取属性 | 比如把 `User` 对象转为 `User.getId()`。 |
| **5. 截断** | **`.limit()`** | 只取前 N 个 | 放在后面可以减少最终处理的数据量。 |
---
### 3. 代码示例:感受顺序的重要性
假设我们要处理一批账单:**找出金额大于 100 的,去重,然后获取它们的 ID。**
```java
List<Integer> result = bills.stream()
.filter(b -> b.getAmount() > 100) // 1. 先过滤 (把不合格的踢走)
.distinct() // 2. 再去重 (防止相同账单处理两次)
.map(Bill::getId) // 3. 转换 (只提取 ID,不再关注整个对象)
.collect(Collectors.toList()); // 4. 收尾
```
---
### 4. 为什么不能乱序?(逻辑对比)
看看下面这两个顺序的区别:
* **顺序 A (推荐)**:`.filter(...).map(...)`
* *解释*:先过滤掉 90% 的坏苹果,再给剩下的 10% 好苹果**贴标签 (map)**。
* *性能*:贴标签的工作量很小。
* **顺序 B (低效)**:`.map(...).filter(...)`
* *解释*:给所有苹果(包括坏的)都**贴上标签**,然后再把贴了标签的坏苹果扔掉。
* *性能*:做了很多没用的“贴标签”动作,浪费 CPU。
---
### 5. 常用组合“公式”总结表
| 需求 | 常用流顺序 |
| --- | --- |
| **清洗数据** | `stream() -> filter() -> distinct() -> collect()` |
| **获取 ID 列表** | `stream() -> map(Entity::getId) -> collect()` |
| **查前 10 名** | `stream() -> sorted() -> limit(10) -> collect()` |
| **判断是否存在** | `stream() -> filter() -> findAny() / isPresent()` |
### 💡 核心记忆点
* **`.stream()`** 是启动开关。
* **中间操作**(filter, map...)是加工过程。
* **终端操作**(collect, count, forEach...)是收工拿结果。
你之前的账单逻辑正是遵循了:**`stream()` (开启) -> `filter()` (去空) -> `distinct()` (去重) -> `collect()` (装箱)**。
你想看看如何用 `.map()` 将一个对象列表快速转换成你需要的 `Map<Integer, Entity>` 结构吗?
- 环境配置
- window怎么配置java环境变量?
- SQL学习
- 字段类型
- 1、 所有可声明的字段类型
- 2、常用的可声明的字段类型
- 创建表和表内字段
- 1、整个创建表语句
- 2、设置id主键
- 3、设置业务主键,唯一索引
- 4、设置业务字段
- 5、普通索引
- 6、唯一索引与普通索引的区别
- 7、表的引擎、字符集、排序规则和注释的设置
- Java基础语法
- 数据类型
- Java中的数据类型
- LocalDate
- 常用的数据类型
- Java 常用数据类型方法
- Java中数组、list、Map、HashMap
- 如何用Map来优化那些复杂的“双重 for 循环”查询?
- Java 8 中steam()操作流
- Java中HashMap和JSON
- Java中的JSONObject
- 工具类
- Java 常用工具类
- Arrays工具类
- Java 时间工具类
- 泛型
- Java中泛型概念
- Java中的泛型容器
- 泛型参数与函数参数的区别
- 推断出泛型实参
- Lambda表达式
- 数据分层
- 异常处理
- Java8 异常处理类总结表
- MyBatis-Plus 常用异常类总结表
- Java高级特性
- Maven
- jib-maven-plugin
- 什么是Spring Boot 的 parent pom?
- maven中各个生命周期的含义
- Spring Boot
- maven与spring boot 的关系
- Java中的连接池
- Spring JDBC
- Spring JDBC的概念
- JdbcTemplate常用的方法
- Spring中Bean的概念
- Spring中的抽象,通俗解释一下
- Spring中的事物
- Spring中的事物,通俗解释一下
- Spring中的事物抽象,常见的有哪些,列举一下
- Spring中常用的事物场景有哪些,列举一下
- Spring事务管理有哪些注解?
- Spring中使用事物处理订单的案例,列举说明一下
- Spring中声明式事务、分布式事务以及编程式事务的区别,列举一下
- 配置文件
- application-properties配置文件
- Spring Boot 的启动
- spring boot项目如何启动?
- 列举一下Spring Boot的启动过程
- SpringApplication.run方法
- Spring Boot 启动时有哪些接口?
- CommandLineRunner
- Spring Boot 的常用注解
- 系统注解
- 表格:系统注解
- @Override
- @Deprecated
- @SuppressWarnnings
- 使用在类名上的注解
- 表格:使用在类名上的注解
- @RestController
- @Controller
- @Service
- @Repository
- @Component
- @Configuration
- @Resource
- @Autowired
- @RequestMapping
- @GetMapping
- @PostMapping
- @Transactional
- @Qualifier
- 使用在方法上的注解
- 表格:使用在方法上的注解
- @RequestBody
- @PathVariable
- @Bean
- @ResponseBody
- @PreAuthorize
- 其他常用注解
- 表格:其他常用注解
- @EnableAutoConfiguration
- @SpringBootApplication
- @EnableScheduling
- @EnableAsync
- @ComponentScan
- @Aspec
- @ControllerAdvice
- @ExceptionHandler
- @Value
- @ConfigurationProperties
- @EnableConfigurationProperties
- @MapperScan
- @ApiOperation
- @Produces
- Validator验证的常用注解
- spring IoC容器
- Spring IoC容器依赖注入实现方式
- 常用依赖
- RESTEasy
- resteasy简介
- RESTEasy框架(依赖)的功能和常用注解
- MyBatis
- 简介
- paginationInterceptor
- @TableName
- @TableId
- @Param
- MyBatis-Plus
- MyBatis-Plus简介
- MyBatis-Plus的工具类
- Mybatis-Plus扩展的工具类和方法
- MyBatis-Plus中最常用的工具类方法
- MyBatis-Plus 中最常用的 4 大核心工具类
- Wrapper条件构造器
- Wrapper条件构造器详解
- Wrapper条件构造器eq等方法的参数说明
- LambdaQueryWrapper与QueryWrapper
- 日期格式是否必须转换
- Lombok
- Lombok作用详解
- @Data
- @Slf4j
- @Builder
- @EqualsAndHashCode
- @Accessors
- Jackson
- Jackson简介
- @JsonFormat
- Jackson高效地在 HashMap 和 JSON 字符串之间进行相互转换
- Hutool
- Hutool简介
- hutool依赖常用的方法
- fastjson2
- fastjson2简介
- UrlBasedCorsConfigurationSource
- 生态相关
- JBoss 社区
- 支付系统
- 1. 初始化mysql数据库流程
- 2. 初始化redis数据库的流程
- 3. 初始化rabbitmq服务
- 环球置业
- 1.模块目录结构分析
- 2. DTO(数据传输层)的核心作用
- 3. VO(视图对象层)
- 4. VO(视图对象层)和 DTO 数据传输层 的区别
