半年吸金934亿!2026具身智能资本大变局:整机“退烧”,谁在“吃肉”?
2026/9/1 7:28:38
我们要计算一个城市列表中,人口超过 10 万的城市总人口数。
recordCity(intpopulation){}List<City>cities=List.of(newCity(100_000),newCity(200_000),newCity(500_000));intsum=0;for(Citycity:cities){intpopulation=city.population();if(population>100_000){sum+=population;}}System.out.println("Sum = "+sum);// 输出:700000这段代码很好地完成了目标,但是命令式的——一步一步告诉程序要做什么。
假设我们扩展Collection接口,给它添加map()和filter()方法,并且它们返回的是Collection:
Collection<Integer>populations=cities.map(city->city.population());Collection<Integer>filteredPopulations=populations.filter(p->p>100_000);intsum=filteredPopulations.sum();看起来很“链式”,很优雅,但有一个严重问题:每一步都要创建中间集合!
map()会遍历所有城市,并创建一个新的集合保存每个城市的人口数。filter()会再遍历这个人口集合,选出符合条件的。sum()会再遍历过滤结果做加总。👉 如果处理上百万城市对象,那么这会造成大量内存分配和垃圾回收压力。
而传统的for循环是一边遍历、一边判断、一边累加的,没有任何中间结构的创建。
intsum=cities.stream().mapToInt(City::getPopulation)// 先映射成人口数.filter(p->p>100_000)// 筛选出人口超 10 万的.sum();// 聚合求和(终端操作)在这段代码中:
.mapToInt()和.filter()都是中间操作,只是“排管道”;.sum()是终端操作,才真正触发数据流动和计算。Stream就像“工厂流水线”,每个操作(map/filter)都是一个加工环节;.sum()、.collect()等终端操作时,才真的开始处理每个数据;💡 不是“先映射完所有人口” ➝ “再筛选” ➝ “再加总”,
而是:每个城市 ➝ 映射 ➝ 判断是否保留 ➝ 累加(即一条龙服务🚀)。
需求:判断是否存在人口超过 100_000 的城市
传统 Collection 风格必须遍历:
booleanexists=cities.map(City::population).filter(p->p>100_000).anyMatch(p->true);// 已经浪费了两步处理而用 Stream 可以做到只看第一个符合条件的城市:
booleanexists=cities.stream().anyMatch(c->c.getPopulation()>100_000);💥 一旦遇到满足条件的城市,就立即返回true,后续不再处理!
| 方式 | map/filter 返回类型 | 是否创建中间集合 | 是否惰性求值 | 是否支持短路 |
|---|---|---|---|---|
Collection.map() | Collection | ✅ 会创建 | ❌ 否 | ❌ 否 |
Stream.map() | Stream | ❌ 不创建 | ✅ 是 | ✅ 是(如 anyMatch) |
👉 正因为Collection 是数据容器,而Stream 是操作流水线,所以map()和filter()被设计在Stream而非Collection。
| 操作类型 | 举例 | 描述 |
|---|---|---|
| 中间操作 | map(),filter(),sorted() | 返回 Stream,不触发计算 |
| 终端操作 | sum(),collect(),forEach() | 返回非 Stream,触发计算 |
stream()实现:计算人口超过 200_000 城市的平均人口;