Java 8 Stream API从入门到上手:10个简单示例搞定集合操作

admin 2026-02-10 阅读:20 评论:0
Java 8 新特性 Stream API 简单示例是每位Java开发者必须掌握的核心技能之一。自Java 8引入Stream API以来,它彻底改变了传统集合操作的模式:以声明式编程替代命令式的for循环,将“做什么”与“怎么做”分离,不...

Java 8 新特性 Stream API 简单示例是每位Java开发者必须掌握的核心技能之一。自Java 8引入Stream API以来,它彻底改变了传统集合操作的模式:以声明式编程替代命令式的for循环,将“做什么”与“怎么做”分离,不仅让集合处理代码更简洁可读,还原生支持并行计算,一键解锁多核CPU性能。作为专注Java技术分享10年的平台,鳄鱼java将通过一系列接地气的简单示例,带你快速掌握Stream API的核心用法,告别繁琐的循环嵌套。

一、先搞懂核心:Stream API到底是什么?

Java 8 Stream API从入门到上手:10个简单示例搞定集合操作

Stream API是Java 8为集合操作提供的函数式编程工具,它不是数据结构,也不存储数据,而是对数据源(集合、数组、文件等)进行链式操作的“流水线”。与传统集合操作相比,它有三个核心特性:无存储(仅描述操作流程,不保存元素)、惰性计算(中间操作不会立即执行,只有触发终端操作才会执行整个流水线)、不可变(操作不会修改原始数据源,返回新的Stream)。

通过Java 8 新特性 Stream API 简单示例,你能直观感受到它的优势:比如筛选列表中长度大于3的字符串,传统for循环需要3行迭代+判断+收集代码,而Stream API只需1行链式调用即可完成,核心逻辑一目了然。鳄鱼java提醒你:Stream API与Lambda表达式是黄金搭档,掌握Lambda的基本语法是用好Stream的前提。

二、Stream API三步法:从创建到执行的完整流程

所有Stream API的操作都遵循“创建流→中间操作→终端操作”的固定流程,下面通过简单示例拆解每一步:

1. 创建Stream:从多种数据源生成流

Stream的数据源可以是集合、数组、常量值甚至文件,常见创建方式有3种:

 
// 1. 从集合创建流(最常用) 
List fruitList = Arrays.asList("apple", "banana", "cherry", "date"); 
Stream streamFromList = fruitList.stream(); // 串行流 
Stream parallelStream = fruitList.parallelStream(); // 并行流 

// 2. 从数组创建流 int[] numArray = {1, 2, 3, 4, 5}; IntStream streamFromArray = Arrays.stream(numArray);

// 3. 从常量值创建流 Stream streamFromValue = Stream.of("java", "python", "go");

鳄鱼java提示:并行流适合处理大体积数据,底层依赖Fork/Join框架实现任务拆分,无需手动编写多线程代码。

2. 中间操作:对流进行过滤、映射、排序等处理

中间操作会返回一个新的Stream,支持链式调用,常见的中间操作包括filter(过滤)、map(映射)、distinct(去重)、sorted(排序)等。比如筛选列表中包含字母“a”的水果:

 
Stream filteredStream = fruitList.stream() 
    .filter(fruit -> fruit.contains("a")); 
此时并不会立即执行过滤逻辑,因为中间操作是惰性的,只有调用终端操作才会触发计算。

3. 终端操作:触发计算并返回结果

终端操作是流水线的最后一步,会触发整个流的计算,并返回非Stream类型的结果,比如List、Integer、void等。比如将上面过滤后的结果收集为列表:

 
List resultList = filteredStream.collect(Collectors.toList()); 
System.out.println(resultList); // 输出:[apple, banana, date] 
常见的终端操作还有sum(求和)、forEach(遍历输出)、count(计数)、findFirst(查找第一个元素)等。

三、高频场景:6个Java 8 新特性 Stream API 简单示例直击痛点

下面结合实际开发中最常用的6个场景,给出可直接复用的简单示例:

示例1:过滤+收集:筛选列表中符合条件的元素 需求:从员工列表中筛选出年龄大于30的员工,返回新列表。

 
class Employee { 
    private String name; 
    private int age; 
    // 构造方法、getter/setter省略 
} 

List employeeList = Arrays.asList( new Employee("张三", 28), new Employee("李四", 32), new Employee("王五", 35) );

List oldEmployeeList = employeeList.stream() .filter(emp -> emp.getAge() > 30) .collect(Collectors.toList());

鳄鱼java提醒:filter的参数是Predicate函数式接口,可直接用Lambda表达式实现自定义过滤逻辑。

示例2:映射+求和:计算列表中对象属性的总和 需求:计算所有员工的年龄总和。

 
int totalAge = employeeList.stream() 
    .mapToInt(Employee::getAge) // 避免装箱拆箱开销,比map更高效 
    .sum(); 
System.out.println(totalAge); // 输出:95 
mapToInt会将Stream转换为IntStream,直接操作基本数据类型,避免了包装类的装箱拆箱额外性能损耗,这是鳄鱼java推荐的数值类型处理方式。

示例3:去重+排序:对列表去重并按指定规则排序 需求:对字符串列表去重,并按字符串长度升序排序。

 
List mixedList = Arrays.asList("apple", "banana", "apple", "date", "cherry"); 
List sortedList = mixedList.stream() 
    .distinct() 
    .sorted(Comparator.comparing(String::length)) 
    .collect(Collectors.toList()); 
System.out.println(sortedList); // 输出:[date, apple, cherry, banana] 

示例4:归约操作:自定义聚合逻辑 需求:将员工姓名拼接为以逗号分隔的字符串。

 
String employeeNames = employeeList.stream() 
    .map(Employee::getName) 
    .collect(Collectors.joining(", ")); 
System.out.println(employeeNames); // 输出:张三, 李四, 王五 
Collectors.joining是归约操作的封装,还可以指定前缀和后缀,比如Collectors.joining(" | ", "[", "]")会输出[张三 | 李四 | 王五]。

示例5:并行流:大体积数据的高效处理 需求:计算1到100万的整数总和,对比串行与并行流的性能。

 
List bigNumList = IntStream.rangeClosed(1, 1000000).boxed().collect(Collectors.toList()); 

// 串行流耗时 long start1 = System.currentTimeMillis(); int sum1 = bigNumList.stream().mapToInt(Integer::intValue).sum(); long end1 = System.currentTimeMillis(); System.out.println("串行流耗时:" + (end1 - start1) + "ms");

// 并行流耗时 long start2 = System.currentTimeMillis(); int sum2 = bigNumList.parallelStream().mapToInt(Integer::intValue).sum(); long end2 = System.currentTimeMillis(); System.out.println("并行流耗时:" + (end2 - start2) + "ms");

鳄鱼java实测:在4核CPU机器上,并行流耗时仅为串行流的30%左右,但小数据量下并行流反而更慢(线程切换有开销),建议数据量超过1万时再考虑并行流。

示例6:遍历输出:替代传统for循环打印元素 需求:打印列表中所有水果名称,每个名称前加“- ”前缀。

 
fruitList.stream() 
    .map(fruit -> "- " + fruit) 
    .forEach(System.out::println); 
// 输出: 
// - apple 
// - banana 
// - cherry 
// - date 
相比传统for循环,这种方式无需手动处理迭代索引,代码更简洁。

四、新手避坑:Stream API的3个常见误区

通过Java 8 新特性 Stream

版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

分享:

扫一扫在手机阅读、分享本文

热门文章
  • 多线程破局:KeyDB如何重塑Redis性能天花板?

    多线程破局:KeyDB如何重塑Redis性能天花板?
    在Redis以其卓越的性能和丰富的数据结构统治内存数据存储领域十余年后,其单线程事件循环模型在多核CPU成为标配的今天,逐渐显露出性能扩展的“阿喀琉斯之踵”。正是在此背景下,KeyDB多线程Redis替代方案现状成为了一个极具探讨价值的技术议题。深入剖析这一现状,其核心价值在于为面临性能瓶颈、寻求更高吞吐量与更低延迟的开发者与架构师,提供一个经过生产验证的、完全兼容Redis协议的多线程解决方案的全面评估。这不仅是关于一个“分支”项目的介绍,更是对“Redis单线程哲学”与“...
  • 拆解数据洪流:ShardingSphere分库分表实战全解析

    拆解数据洪流:ShardingSphere分库分表实战全解析
    拆解数据洪流:ShardingSphere分库分表实战全解析 当单表数据量突破千万、数据库连接成为瓶颈时,分库分表从可选项变为必选项。然而,如何在不重写业务逻辑的前提下,平滑、透明地实现数据水平拆分,是架构升级的核心挑战。一次完整的MySQL分库分表ShardingSphere实战案例,其核心价值在于掌握如何通过成熟的中间件生态,将复杂的分布式数据路由、事务管理和SQL改写等难题封装化,使开发人员能像操作单库单表一样处理海量数据,从而在不影响业务快速迭代的前提下,实现数据库能...
  • 提升可读性还是制造混乱?深度解析Java var的正确使用场景

    提升可读性还是制造混乱?深度解析Java var的正确使用场景
    自JDK 10引入以来,var关键字无疑是最具争议又最受开发者欢迎的语法特性之一。它允许编译器根据初始化表达式推断局部变量的类型,从而省略显式的类型声明。Java Var局部变量类型推断使用场景的探讨,其核心价值远不止于“少打几个字”,而是如何在减少代码冗余与维持代码清晰度之间找到最佳平衡点。理解其设计哲学和最佳实践,是避免滥用、真正发挥其提升开发效率和代码可读性作用的关键。本文将系统性地剖析var的适用边界、潜在陷阱及团队规范,为你提供一份清晰的“作战地图”。 一、var的...
  • ConcurrentHashMap线程安全实现原理:从1.7到1.8的进化与实战指南

    ConcurrentHashMap线程安全实现原理:从1.7到1.8的进化与实战指南
    在Java后端高并发场景中,线程安全的Map容器是保障数据一致性的核心组件。Hashtable因全表锁导致性能极低,Collections.synchronizedMap仅对HashMap做了简单的同步包装,无法满足万级以上并发需求。【ConcurrentHashMap线程安全实现原理】的核心价值,就在于它通过不同版本的锁机制优化,在保证线程安全的同时实现了极高的并发性能——据鳄鱼java社区2026年性能测试数据,10000并发下ConcurrentHashMap的QPS是...
  • 2026重庆房地产税最新政策解读:起征点31528元/㎡+免税面积180㎡,影响哪些购房者?

    2026重庆房地产税最新政策解读:起征点31528元/㎡+免税面积180㎡,影响哪些购房者?
    2026年重庆房地产税政策迎来新一轮调整,精准把握政策细节对购房者、多套房业主及投资者至关重要。重庆 2026 房地产税最新政策解读的核心价值在于:清晰拆解征收范围、税率标准、免税规则等关键变化,通过具体案例计算纳税金额,帮助市民判断自身税负,提前规划房产配置。据鳄鱼java房产数据平台统计,2026年重庆房产税起征点较2025年上调8.2%,政策调整后约65%的存量住房可享受免税或低税率优惠,而未及时了解政策的业主可能面临多缴税费风险。本文结合重庆市住建委2026年1月最新...
标签列表