你还在用迭代器处理集合吗?试试Stream,真香!

简介: 首先给大家看一段代码,让大家直观感受下 Java7 和 Java8 遍历处理集合的不同Dish 是一个菜肴对象,calories 属性表示该菜品的卡路里值,name 则是菜品的名称。我们需要过滤出卡路里小于400、然后根据卡路里值升序、接着拿到他们的名称列表并返回

首先给大家看一段代码,让大家直观感受下 Java7 和 Java8 遍历处理集合的不同


Dish 是一个菜肴对象,calories 属性表示该菜品的卡路里值,name 则是菜品的名称。我们需要过滤出卡路里小于400、然后根据卡路里值升序、接着拿到他们的名称列表并返回


Java7

public static List<String> getLowCaloricDishesNamesInJava7(List<Dish> dishes){  
    List<Dish> lowCaloricDishes = new ArrayList<>();  
    for(Dish d: dishes){  
        if(d.getCalories() < 400){  
            lowCaloricDishes.add(d);  
        }  
    }  
    List<String> lowCaloricDishesName = new ArrayList<>();  
    Collections.sort(lowCaloricDishes, new Comparator<Dish>() {  
        public int compare(Dish d1, Dish d2){  
            return Integer.compare(d1.getCalories(), d2.getCalories());  
        }  
    });  
    for(Dish d: lowCaloricDishes){  
        lowCaloricDishesName.add(d.getName());  
    }  
    return lowCaloricDishesName;  
}  

Java8

public static List<String> getLowCaloricDishesNamesInJava8(List<Dish> dishes){  
    return dishes.stream()  
        .filter(d -> d.getCalories() < 400)  
        .sorted(comparing(Dish::getCalories))  
        .map(Dish::getName)  
        .collect(toList());  
}  

如果需要多核并行处理,则只需调用 dishes.parallelStream() 即可


在 Java8 之前,程序员需要通过 2次遍历 + 一次集合排序才能完成的工作,Java8 只需要一个链式调用就可以解决。这就是 Stream 的强大之处


image.png


认识流

流是什么

流是 Java API 的新成员,允许程序员以声明式的方式处理集合数据,并且支持链式调用、支持并行处理。用流处理的集合数据高效且易读。Stream 的 10 种创建方式,这篇推荐你看下。更多Java8新特性教程关注公众号Java技术栈回复Java获取。


流与集合的异同

集合的主要功能是以一定的时间和空间复杂度存储和访问元素,而流主要是用于元素计算


集合中的元素可以随意添加和删除,而流不能添加和删除元素


流的元素是按需计算的,只有当用到时他才会参与计算,而集合中的元素必须提前全都准备好


流只能遍历一次,下面的代码会报错 java.lang.IllegalStateException: stream has already been operated upon or closed 流已经被消费掉

List<String> names = Arrays.asList("Java8", "Lambdas", "In", "Action");  
Stream<String> s = names.stream();  
s.forEach(System.out::println);  
s.forEach(System.out::println);  

集合采用外部迭代,流采用内部迭代。内部迭代意味着 Java 可以替你选择更优的迭代策略和并行处理。而外部迭代如果程序员想着做个更有的迭代/采用并行就相当于“下次一定”😅了

流操作分类

对流的操作可以分为两类,可以继续执行下一个流操作的称为中间操作(方法的返回值是 Stream),关闭流的操作称为终止操作。


中间操作

除非流水线上执行终端操作,否则中间操作不会执行任何处理。流会对中间操作进行合并、短路等优化


终端操作

终端操作会从流的流水线生成结果,返回一个非 stream 的任意类型值


使用流

筛选和切片

筛选

filter(Predicate predicate) 方法可以将流中满足某条件的元素筛选出来。该方法接收一个谓词函数,返回流。比如要选出某个苹果集合中红色的苹果

List<Apple> appleList = new ArrayList<>();  
List<Apple> redAppleList = appleList.stream().filter(a -> "red".equals(a.getColor())).collect(Collectors.toList());  

去重

distinct() 方法会根据元素的 hashCode() 和 equals() 方法对流中元素进行去重操作


截断

limit(n) 方法会返回流的前 n 个元素,对于有序集合List,流会按照添加顺序返回前 n 个元素,而无序集合则不会


跳过

skip(n) 方法会跳过流的前 n 个元素,可以通过 skip(m).limit(n) 返回列表中第 m - (m+n) 区间的元素,类似与 mysql 中的 limit m,n


映射

对流中的每个元素应用函数

map(Function mapper) 方法。该方法接收一个 Function 函数,对流中的每一个元素使用。然后可以返回任意类型的对象。有了该方法,就可以结合 Lambda 表达式对集合中的元素使用函数进行各种转换


流的扁平化

flatMap() 可以将流操作中多个流合并成一个流的多个元素。


举个例子:集合 words 有两个单词,现在想获得[H, e, l, o, W, r, d] 在 split 方法执行完毕后,返回的是 Stream(String[]) 对象,而此时如果执行 map 方法,返回的就是多个流的集合(这个例子中就是两个 Stream(String)),这时是无法继续接下来的 distinct 操作的,因此需要 flatMap 将两个 Stream扁平化成一个 Stream,然后进行操作

List<String> words = Arrays.asList("Hello", "World");  
List<String> charList = words.stream().map(word -> word.split("")).flatMap(Arrays::stream).distinct().collect(Collectors.toList());  

该方法的方法声明 flatMap(Function> mapper) 中可以看出,他所使用的函数式接口 Function 第二个泛型 R 必须是 Stream流。即函数式接口的抽象方法返回值必须是 Stream流及其子类对象。


查找和匹配

检查谓词是否至少匹配一个元素

anyMatch 方法可以回答“流中是否存在至少一个复合谓词条件的元素”返回 boolean 类型的值,因此是一个终端操作,例如

List<Integer> num = Arrays.asList(1, 2, 3, 4, 5, 6);  
if (num.stream().anyMatch(n -> n % 3 == 0)) {  
    System.out.println("集合中有元素是3的整数倍");  
}  

控制台会输出'集合中有元素是3的整数倍',因为集合中 3、6都是3的整数倍,符合谓词的条件。


检查谓词是否匹配所有元素

allMatch 方法和 anyMatch 方法原理类似,但是它仅当所有元素满足谓词条件时,返回 true。


noneMatch 与 allMatch 正好相反,仅当所有元素不满足谓词条件时,返回 true


ps:和 && || 运算符类似,以上三个操作都用到了短路的思想来提高效率。


查找元素

findAny() 该方法返回当前流中的任意元素,可以和其他流操作结合使用,这里需要注意 findAny() 返回的结果被 Optional 所包裹,Optional是 Java8 为优雅的避免 NPE 所采用的新 API,这里需要说明的就是 Optional.ifPresent(Consumer consumer) 表示当 Optional 包裹的元素不为空时,执行 consumer

num.stream().filter(n -> n > 2).findAny().ifPresent(System.out::println);  

findFirst() 该方法返回当前流中的第一个元素,一般也和其他流操作(例如 filter() 过滤)结合使用。与 findAny() 不同的是,他一定返回有序集合的第一个满足条件的元素。当然有得必有失,作为代价,findFirst() 在并行处理时限制更多一些。


归约

元素求和

reduce(T identity, BinaryOperator accumulator); 方法接收两个参数:identity 初始值,accumulator 对两个数的操作。例如求集合中数字的和:

num.stream().reduce(0, (a, b) -> a + b) // 计算完成,返回 21  

ps:Lambda 表达式 (a, b) -> a + b) 中 a 是上一轮执行完后的累计值,b 是本次循环流中的元素。通过累加就可以计算出数字的和。更多Java8新特性教程关注公众号Java技术栈回复Java获取。


最大值和最小值

reduce 方法不仅可以求和、求积。甚至可以计算最大值、最小值。

num.stream().reduce(Integer::max);  
num.stream().reduce(Integer::min);  

总结

流是 Java API 的新成员,允许程序员以声明式的方式处理集合数据,并且支持链式调用、支持并行处理。用流处理的集合数据高效且易读。


流的API中可以分为两大类,中间操作和终端操作,中间操作返回流对象,可以链式调用,终端操作则返回非流对象。


流提供了很多方便的API,如筛选 filter、去重 distinct、截断 limit、跳过 skip、函数转换 map、扁平化 flatMap、判断流中是否有任意元素符合要求 anyMatch、是否所有元素都符合要求 allMatch、是否所有元素都不符合要求 noneMatch、查找元素 findAny findFirst、累计式的计算元素 reduce


相关文章
|
6月前
|
存储 人工智能 弹性计算
2026阿里云活动汇总:云服务器、AI产品、优惠券等十大核心活动内容简介
2026年阿里云热门活动汇总:涵盖开年焕新、快速部署OpenClaw、AI焕新季、99计划等。活动提供低至3折的云服务器、9.9元起的AI助理部署、千问大模型特惠等。用户可享受主机病毒防护、文件备份、免费试用超160款产品等权益。此外,还有大模型全量抵扣、GPU云服务器加速、精选AI产品组合购等优惠。活动旨在助力企业和开发者高效上云、降低成本、快速创新,实现数字化转型与AI应用落地。
827 4
|
6月前
|
数据采集 运维 监控
一文读懂机床数据采集:数控系统适配、核心参数与落地实践
本文系统解析机床数据采集的落地难题与实践路径,覆盖多品牌数控系统适配、200+核心参数毫秒级采集、断网续传等关键技术,并详解生产透明化、OEE提升、刀具全周期管理、预测性维护等六大应用场景,提供与MES/ERP无缝对接方案,助力机加工厂低成本实现数字化升级。
964 3
|
6月前
|
人工智能 自然语言处理 大数据
2026年1688开店真能赚到钱吗?最新投入产出全解析,AI红利期已至!
2026年1688全面AI化,开店年费9988元起(诚信通AI版),升级选项达3.68万–10.68万元/年;另需数字推广(约3万/年)及人力投入。平台推出“三保”服务(保5万访客、500询盘、300订单),未达标返6688元红包。AI正驱动决策、组织与竞争力三大位移,助力源头工厂智能升级。
|
5月前
|
人工智能 Python
别再乱问AI了!掌握这3个“指令性提示词”,效率提升300%
别再乱问AI了!掌握这3个“指令性提示词”,效率提升300%
862 5
|
5月前
|
机器学习/深度学习 人工智能 安全
Kimi、Cursor、Chroma:三条路线,为什么最后走到同一套训练方法?
本文揭示Agent训练正走向统一范式:Kimi、Cursor、Chroma不约而同采用“生产环境训练+可验证奖励+强基座微调+异步轨迹更新”路径,标志行业从探索迈入收敛。核心转向“让模型做事”而非“背答案”,Prompt工程正被任务驱动的Agent范式取代。
|
6月前
|
弹性计算 测试技术 Linux
阿里云服务器9.9元1个月、38元一年轻量,200M峰值带宽,你抢到了吗?
阿里云新用户专享:2核2G轻量服务器,200M峰值带宽、40G ESSD、不限流量,秒杀价38元/年!每日10:00、15:00开抢,限1台。抢不到可68元购同款,或领券低至44元。需提前实名、选好地域与镜像,手速+技巧缺一不可。(239字)
731 1
|
6月前
|
JSON 容灾 测试技术
从 0 到 1 搭建高可用服务治理体系:路由、灰度、流量调度架构全解析
本文深入解析微服务治理三大核心能力:路由(精准导航)、灰度(风险可控发布)与流量调度(动态自适应调控),剖析其底层原理、分层架构、协同机制及落地陷阱,提供可复用的代码实现与最佳实践,助力构建高可用、可演进的服务治理体系。
453 1
|
6月前
|
存储 人工智能 5G
什么是云渲染?3 分钟读懂高效渲染新范式!
云渲染依托云端超算集群,将高负载渲染任务远程处理,实现多任务并行、效率跃升。兼容Maya/3ds Max/Blender等全主流软件,支持自定义插件;释放本地资源,降低硬件损耗;
|
5月前
|
存储 安全 大数据
信息系统与新一代信息技术知识体系
本知识体系系统梳理信息化内涵、信息系统全生命周期及五层逻辑结构,涵盖诺兰模型、OSI/TCP/IP网络基础、数据库与大数据技术、云边端协同架构,并深入解析物联网、区块链、AI、数字孪生等新一代信息技术及其在新基建中的融合应用。(239字)
393 0
|
人工智能 关系型数据库 分布式数据库
客户说|哔哩哔哩基于阿里云PolarDB与千问大模型构建全域内容洞察新框架
哔哩哔哩联合阿里云 PolarDB for AI,构建“大模型+小模型”协同的全域内容洞察体系,基于去标识化公开互动数据,实现视频、评论等内容的结构化分析,精准识别品牌、类目、用户反馈属性,助力营销效果量化与策略优化。