🎉 恭喜你发现了宝藏!

Java 8 Stream 流处理从入门到实战,让集合操作更优雅

温馨提示:本文最后更新于2025-12-19 18:25:57,某些文章具有时效性,若有错误或已失效,请在下方留言或联系社长

前言

Java 8 之前,我们处理集合(List、Map、Set)时,往往需要写大量的循环、判断代码,不仅冗余且可读性差。而 Java 8 引入的Stream 流,可以让我们以声明式的方式处理集合,代码更简洁、更优雅,也是现在 Java 开发面试和工作中的高频考点。这篇文章就带大家从基础到实战,彻底掌握 Stream 流的使用。

一、什么是 Java 8 Stream?

Stream(流)是 Java 8 提供的一个新特性,它并不是一个数据结构,也不存储数据,而是对集合数据进行处理的管道。我们可以把 Stream 理解为一个 “数据流”,通过一系列的操作(过滤、映射、排序、聚合等),最终得到我们想要的结果。
Stream 的核心特点:
  1. 不存储数据:Stream 只是操作数据的工具,数据源依然是原集合。
  2. 惰性执行:中间操作(如 filter、map)不会立即执行,只有调用终止操作(如 collect、forEach)时才会执行。
  3. 一次性使用:Stream 只能被消费一次,消费后就会失效,如需再次操作需重新创建。
  4. 并行处理:支持并行流,能充分利用多核 CPU 提升处理效率。

二、Stream 的使用步骤

使用 Stream 通常分为三个步骤:
  1. 创建 Stream:从集合、数组等数据源中获取流。
  2. 中间操作:对数据流进行过滤、映射、排序等处理(可多个中间操作链式调用)。
  3. 终止操作:触发流的执行,得到最终结果(如收集为集合、计算统计值等)。

三、Stream 实战:从基础到进阶

首先,我们定义一个实体类user,作为后续操作的数据源:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 用户实体类(使用Lombok简化代码,需引入依赖)
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    // 用户ID
    private Long id;
    // 用户名
    private String name;
    // 年龄
    private Integer age;
    // 城市
    private String city;
    // 薪资
    private Double salary;
}

注:如果未使用 Lombok,可以手动编写 getter、setter、构造方法和 toString 方法。

1. 创建 Stream
我们先创建一个用户列表作为数据源,然后获取 Stream:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class StreamDemo {
    public static void main(String[] args) {
        // 1. 初始化数据源
        List<User> userList = new ArrayList<>();
        userList.add(new User(1L, "张三", 25, "北京", 10000.0));
        userList.add(new User(2L, "李四", 30, "上海", 15000.0));
        userList.add(new User(3L, "王五", 28, "北京", 12000.0));
        userList.add(new User(4L, "赵六", 35, "广州", 20000.0));
        userList.add(new User(5L, "孙七", 25, "上海", 9000.0));

        // 2. 创建Stream的几种方式
        // 方式1:从集合创建(最常用)
        Stream<User> stream1 = userList.stream(); // 串行流
        Stream<User> parallelStream = userList.parallelStream(); // 并行流

        // 方式2:从数组创建
        String[] names = {"张三", "李四", "王五"};
        Stream<String> stream2 = Stream.of(names);

        // 方式3:直接创建流
        Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5);
    }
}
2. 中间操作:过滤、映射、排序
中间操作会返回一个新的 Stream,支持链式调用,以下是常用的中间操作:
import java.util.List;
import java.util.stream.Collectors;

public class StreamMiddleOperation {
    public static void main(String[] args) {
        // 初始化数据源(同上,这里省略,实际使用时需添加)
        List<User> userList = initUserList();

        // 示例1:过滤:筛选出北京的用户
        List<User> beijingUsers = userList.stream()
                .filter(user -> "北京".equals(user.getCity())) // 过滤条件
                .collect(Collectors.toList()); // 终止操作:收集为List
        System.out.println("北京的用户:" + beijingUsers);

        // 示例2:映射:获取所有用户的姓名
        List<String> userNameList = userList.stream()
                .map(User::getName) // 将User对象映射为姓名字符串
                .collect(Collectors.toList());
        System.out.println("所有用户姓名:" + userNameList);

        // 示例3:排序:按年龄升序排序,年龄相同按薪资降序
        List<User> sortedUsers = userList.stream()
                .sorted((u1, u2) -> {
                    if (u1.getAge().equals(u2.getAge())) {
                        return u2.getSalary().compareTo(u1.getSalary());
                    }
                    return u1.getAge().compareTo(u2.getAge());
                })
                .collect(Collectors.toList());
        System.out.println("排序后的用户:" + sortedUsers);

        // 示例4:去重:根据年龄去重(需注意:自定义对象去重需重写equals和hashCode)
        List<Integer> distinctAges = userList.stream()
                .map(User::getAge)
                .distinct()
                .collect(Collectors.toList());
        System.out.println("去重后的年龄:" + distinctAges);

        // 示例5:限制:只取前3个用户
        List<User> limitUsers = userList.stream()
                .limit(3)
                .collect(Collectors.toList());
        System.out.println("前3个用户:" + limitUsers);
    }

    // 初始化用户列表的工具方法
    private static List<User> initUserList() {
        List<User> userList = new ArrayList<>();
        userList.add(new User(1L, "张三", 25, "北京", 10000.0));
        userList.add(new User(2L, "李四", 30, "上海", 15000.0));
        userList.add(new User(3L, "王五", 28, "北京", 12000.0));
        userList.add(new User(4L, "赵六", 35, "广州", 20000.0));
        userList.add(new User(5L, "孙七", 25, "上海", 9000.0));
        return userList;
    }
}
3. 终止操作:聚合、收集、遍历
终止操作会触发 Stream 的执行,并返回一个非 Stream 的结果,以下是常用的终止操作:
import java.util.*;
import java.util.stream.Collectors;

public class StreamTerminalOperation {
    public static void main(String[] args) {
        List<User> userList = initUserList();

        // 示例1:遍历:打印所有用户信息
        userList.stream().forEach(user -> System.out.println(user));

        // 示例2:聚合:统计用户总数
        long count = userList.stream().count();
        System.out.println("用户总数:" + count);

        // 示例3:聚合:获取薪资最高的用户
        Optional<User> maxSalaryUser = userList.stream()
                .max(Comparator.comparingDouble(User::getSalary));
        maxSalaryUser.ifPresent(user -> System.out.println("薪资最高的用户:" + user));

        // 示例4:收集:按城市分组
        Map<String, List<User>> userGroupByCity = userList.stream()
                .collect(Collectors.groupingBy(User::getCity));
        System.out.println("按城市分组:" + userGroupByCity);

        // 示例5:收集:计算薪资总和
        Double totalSalary = userList.stream()
                .collect(Collectors.summingDouble(User::getSalary));
        System.out.println("薪资总和:" + totalSalary);

        // 示例6:匹配:判断是否有年龄大于30的用户
        boolean hasAgeGreater30 = userList.stream().anyMatch(user -> user.getAge() > 30);
        System.out.println("是否有年龄大于30的用户:" + hasAgeGreater30);
    }

    // 初始化用户列表的工具方法(同上,省略)
    private static List<User> initUserList() {
        // 代码同上,此处省略
    }
}

四、Stream 的优势与注意事项

1. 优势
  • 代码更简洁:省去了繁琐的循环和判断,一行代码即可完成复杂的集合操作。
  • 可读性更高:声明式的语法让代码意图更清晰,便于团队协作和维护。
  • 支持并行处理:并行流可以自动利用多核 CPU,提升大数据量处理的效率。
2. 注意事项
  • Stream 不可复用:一旦执行了终止操作,Stream 就会关闭,无法再次使用。
  • 避免在中间操作中修改数据源:这会导致不可预测的结果,违反函数式编程的原则。
  • 并行流的使用场景:只有当数据量较大且操作耗时较长时,使用并行流才有意义;小数据量下,并行流的线程开销可能反而降低效率。

五、总结

Java 8 Stream 流是处理集合的利器,它将函数式编程思想引入 Java,让集合操作变得更优雅、更高效。本文从 Stream 的概念、使用步骤到实战案例,详细讲解了 Stream 的核心用法,包括创建流、中间操作和终止操作。掌握这些知识点,能让你在实际开发中减少冗余代码,提升开发效率。
最后,建议大家多动手实践,结合实际业务场景使用 Stream,才能真正将这个知识点融会贯通。
此文章仅供学习 请在下载24小时内删除。
© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
评论 抢沙发

    也~一个评论的都没有