NIUCLOUD是一款SaaS管理后台框架多应用插件+云编译。上千名开发者、服务商正在积极拥抱开发者生态。欢迎开发者们免费入驻。一起助力发展! 广告
`.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>` 结构吗?