巧用Java 8 Stream流简化集合操作

简介: 本文详解Java 8 Stream API如何简化集合操作:通过filter筛选、map转换、collect收集等声明式方法,一行代码替代冗长for循环。以成年用户处理为例,对比传统写法,突出Stream在可读性、简洁性与可维护性上的显著优势。(239字)

在Java开发中,集合处理是日常高频操作。传统的for循环遍历、筛选、转换不仅代码冗余,可读性也差。Java 8引入的Stream流(Stream API)能以声明式的方式处理集合,让代码更简洁、易维护。本文通过简单示例,带你快速上手Stream流的核心用法。

场景说明

假设我们有一个用户列表,需要完成三个常见操作:

  1. 筛选出年龄大于18岁的成年用户;
  2. 提取这些用户的姓名并拼接成字符串;
  3. 统计成年用户的数量。

传统循环实现

先看传统for循环的写法,感受一下冗余的代码:

import java.util.ArrayList;
import java.util.List;

// 定义用户实体类
class User {
   
    private String name;
    private int age;

    // 构造方法
    public User(String name, int age) {
   
        this.name = name;
        this.age = age;
    }

    // getter方法
    public String getName() {
   
        return name;
    }

    public int getAge() {
   
        return age;
    }
}

public class StreamDemo {
   
    public static void main(String[] args) {
   
        // 初始化用户列表
        List<User> userList = new ArrayList<>();
        userList.add(new User("张三", 20));
        userList.add(new User("李四", 17));
        userList.add(new User("王五", 25));
        userList.add(new User("赵六", 16));

        // 传统方式:筛选成年用户、提取姓名、统计数量
        List<String> adultNames = new ArrayList<>();
        int adultCount = 0;
        for (User user : userList) {
   
            if (user.getAge() > 18) {
    // 筛选条件
                adultNames.add(user.getName()); // 提取姓名
                adultCount++; // 统计数量
            }
        }

        // 拼接姓名
        String nameStr = String.join(", ", adultNames);
        System.out.println("成年用户姓名:" + nameStr);
        System.out.println("成年用户数量:" + adultCount);
    }
}

Stream流实现

用Stream流重构后,代码更简洁,逻辑更清晰:

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

// 复用上面的User实体类
public class StreamOptDemo {
   
    public static void main(String[] args) {
   
        // 初始化用户列表
        List<User> userList = new ArrayList<>();
        userList.add(new User("张三", 20));
        userList.add(new User("李四", 17));
        userList.add(new User("王五", 25));
        userList.add(new User("赵六", 16));

        // Stream流方式:一站式完成筛选、转换、统计
        // 1. 筛选成年用户并提取姓名
        List<String> adultNames = userList.stream()
                .filter(user -> user.getAge() > 18) // 筛选条件:年龄>18
                .map(User::getName) // 提取姓名(方法引用)
                .collect(Collectors.toList()); // 转换为List

        // 2. 统计成年用户数量
        long adultCount = userList.stream()
                .filter(user -> user.getAge() > 18)
                .count(); // 直接统计数量

        // 3. 拼接姓名
        String nameStr = adultNames.stream().collect(Collectors.joining(", "));

        System.out.println("成年用户姓名:" + nameStr);
        System.out.println("成年用户数量:" + adultCount);
    }
}

代码解释

  1. stream():将集合转换为Stream流,开启流式操作;
  2. filter():接收Lambda表达式作为筛选条件,只保留符合条件的元素;
  3. map():对元素进行转换,这里通过User::getName(方法引用)提取用户姓名;
  4. collect():将流转换为指定集合(如Collectors.toList())或拼接字符串(Collectors.joining());
  5. count():统计流中元素的数量,返回long类型。

运行结果

两种写法的运行结果一致:

成年用户姓名:张三, 王五
成年用户数量:2

总结

  1. Stream流以声明式编程替代传统命令式循环,代码更简洁、可读性更高;
  2. 核心方法filter()(筛选)、map()(转换)、collect()(收集)是Stream流的高频用法;
  3. Stream流支持链式调用,可一站式完成多步集合操作,减少中间变量的定义。

Stream流不仅能简化集合操作,还支持并行流(parallelStream())提升大数据量处理效率,是Java 8及以上版本必备的核心技能。

相关文章
|
6月前
|
存储 缓存 Java
Java 对象内存布局:从堆内存储到伪共享优化的底层真相
Java对象内存布局是JVM核心基础:含对象头(Mark Word+Klass指针)、实例数据(字段重排序优化)和对齐填充(8字节对齐)。它直接影响内存占用、GC效率、锁升级与伪共享性能。掌握此机制,是深入理解并发优化(如@Contended)、指针压缩及高性能编程的必经之路。(239字)
647 111
|
7月前
|
SQL 缓存 算法
Java 内存模型与 volatile:并发底层的轻量级同步核心
`volatile` 是JMM核心轻量级同步关键字,通过内存屏障禁用重排、借助MESI协议保障可见性,精准解决可见性与有序性(不保证原子性),是DCL单例、状态标志等场景的基石,堪称高效并发编程的“轻量级钥匙”。(239字)
433 7
|
6月前
|
人工智能 安全 编译器
C语言的「隐形时序契约」:序列点、副作用与求值顺序终极拆解
本文深入解析C语言中极易被忽视的“序列点”机制,揭示Debug/Release模式差异、跨平台结果不一致等玄学bug的根源——未定义行为(UB)。从副作用定义出发,系统梳理7类标准序列点,剖析4大高频陷阱(如`i=i++ + ++i`),并提供6条安全编码铁律,助你写出稳定、可移植的C代码。(239字)
576 11
|
6月前
|
缓存 前端开发 JavaScript
前端渲染性能的底层逻辑:跳出重排重绘的表层认知
本文揭示前端渲染优化的本质:性能瓶颈不在“重排重绘”本身,而在于浏览器渲染流水线(JS→样式→布局→绘制→合成)的**触发频次与全链路开销**。主流框架的优化逻辑——批量更新、精准更新、合成层隔离——正是围绕降低流水线调用成本展开。落地只需三招:收敛更新时机、善用编译期优化、慎用合成层。
|
6月前
|
编译器 C语言 开发者
C语言「常量折叠」:编译器的隐形优化陷阱,90%开发者踩过的常量计算骗局
C语言常量折叠是编译器在编译期预计算常量表达式(如`10+20→30`)的优化机制,可提升运行效率,却易致调试困惑、嵌入式寄存器操作失效等陷阱。关键要分清字面量/宏/enum(真常量)与`const`变量(仅只读),慎用宏、禁用`volatile`参与折叠,并合理控制优化等级。
|
6月前
|
存储 安全 算法
C语言高频错误实例对比:8段代码帮你避开90%的坑
本文精选8组典型C语言错误与正确代码对比,直击数组越界、字符串溢出、野指针、内存泄漏、有无符号混用、返回局部地址、sizeof误用、未定义行为等高频陷阱,以实例培养安全编码直觉。(239字)
|
6月前
|
缓存 编译器 程序员
C语言深度解析:restrict关键字——编译器性能优化的终极钥匙
C99的`restrict`关键字是C语言性能优化的“终极钥匙”:它向编译器承诺指针独占访问内存,彻底解决同类型指针别名问题,解锁循环向量化、寄存器缓存等激进优化。滥用致未定义行为,善用则性能飙升数倍——这才是真正高阶C程序员的必修课。(239字)
|
6月前
|
存储 C语言 内存技术
C语言深度解析:大小端字节序——多字节数据的底层存储规则
大小端指CPU对多字节数据在内存中的存放顺序:大端高字节存低地址,小端反之。x86/ARM默认小端,网络字节序统一为大端。跨平台、网络通信、二进制协议开发中必须显式处理字节序转换,否则数据解析必错。
1242 138
|
6月前
|
存储 安全 编译器
C语言深度解析:变长数组(VLA)的底层逻辑与避坑指南
变长数组(VLA)是C99引入的栈上动态数组,长度运行时确定,访问快但无安全检查。易致栈溢出、野指针、跨平台兼容问题,仅适用于小尺寸、短生命周期场景,大数组务必用malloc。
728 38
|
6月前
|
JavaScript 前端开发 Java
闭包:被误解最深的 JavaScript 特性
闭包本质是JS保留作用域上下文的能力,非语法而是引擎机制。它支撑私有变量封装、模块化与防抖/节流等高级模式。内存泄漏主因是未及时解除引用,而非闭包本身。理解闭包,方懂JS作用域与生命周期精髓。(239字)