欢迎光临
我们一直在努力

Java 流式编程(Stream)完整详解

目录

一、基础概念

1. 流的三要素

2. 流的特点

二、创建 Stream(数据源)

1. 从集合创建(最常用)

2. 从数组创建

3. 直接创建空流 / 指定元素流

4. 无限流(生成 / 迭代)

三、中间操作(Intermediate)

1. 常用无状态操作(不依赖前后元素)

filter 过滤

map 映射(类型转换 / 字段提取)

flatMap 扁平化映射(拆分层级)

peek 查看 / 调试流

2. 常用有状态操作(依赖全部元素 / 顺序)

distinct 去重

sorted 排序

limit /skip 截取 / 跳过

四、终端操作(Terminal)

1. forEach /forEachOrdered 遍历

2. collect 收集(最核心)

① 转为 List / Set / 数组

② 拼接字符串 joining

③ 分组 groupingBy(类似 SQL group by)

④ 分区 partitioningBy(二分区:true/false)

⑤ 聚合统计(count、max、min、avg、sum)

3. 匹配操作(返回 boolean)

4. 查找操作

5. 规约 reduce(聚合计算,自定义累加)

五、数值流(IntStream / LongStream / DoubleStream)

1. 转换数值流

2. 范围创建数值流

3. 数值便捷计算

六、并行流 parallelStream

1. 开启方式

2. 原理

3. 注意事项(坑)

七、完整实战示例(传统循环 VS 流式)

传统 for 循环

Stream 流式写法(一行链式)

八、常见避坑总结

九、Java 9+ 新增增强(拓展)


Java 8 引入 Stream 流,用于集合 / 数组的链式、函数式数据处理,替代传统循环遍历,代码更简洁、可读性强,支持并行计算。

核心定位:不是数据结构,是数据的「处理管道」,不存储数据,只操作数据源。


一、基础概念

1. 流的三要素

  • 数据源:集合、数组、IO 流、生成器等
  • 中间操作:链式调用,延迟执行(返回新 Stream),可多次叠加
  • 终端操作:触发整个流执行,关闭流(流只能用一次)
  • 2. 流的特点

    • 惰性求值:中间操作直到终端调用才执行
    • 单向不可逆:流一旦终端消费,不能重复使用
    • 不修改原数据源:所有操作返回新结果,原集合不变
    • 支持并行流:简单切换即可利用多线程

    二、创建 Stream(数据源)

    1. 从集合创建(最常用)

    List<String> list = Arrays.asList("A", "B", "C");
    // 顺序流
    Stream<String> stream = list.stream();
    // 并行流
    Stream<String> parallelStream = list.parallelStream();

    2. 从数组创建

    String[] arr = {"1", "2", "3"};
    Stream<String> stream = Arrays.stream(arr);

    3. 直接创建空流 / 指定元素流

    // 空流
    Stream<String> empty = Stream.empty();
    // 可变参数创建流
    Stream<Integer> numStream = Stream.of(1, 2, 3, 4);

    4. 无限流(生成 / 迭代)

    常用于造测试数据,必须配合 limit 截断,否则死循环

    // 迭代:从0开始,每次+2
    Stream.iterate(0, n -> n + 2).limit(5).forEach(System.out::println);

    // 生成:随机数
    Stream.generate(Math::random).limit(3).forEach(System.out::println);


    三、中间操作(Intermediate)

    返回 Stream,可链式拼接,延迟执行,分为:无状态、有状态。

    1. 常用无状态操作(不依赖前后元素)

    filter 过滤

    筛选符合条件元素,参数 Predicate 断言

    List<Integer> nums = Arrays.asList(1,2,3,4,5,6);
    nums.stream()
    .filter(n -> n > 3) // 保留大于3的数
    .forEach(System.out::println);

    map 映射(类型转换 / 字段提取)

    一对一转换,参数 Function

    // 数字转字符串
    nums.stream().map(String::valueOf).forEach(System.out::println);

    // 实体类提取字段(示例)
    class User { String name; }
    List<User> userList = new ArrayList<>();
    userList.stream().map(User::getName).forEach(System.out::println);

    flatMap 扁平化映射(拆分层级)

    一对多,把流中的集合 / 数组拆解为单个元素,解决嵌套集合

    List<List<String>> nested = Arrays.asList(
    Arrays.asList("a","b"),
    Arrays.asList("c","d")
    );
    // 扁平化:两层集合 → 单层流
    nested.stream()
    .flatMap(Collection::stream)
    .forEach(System.out::println);

    peek 查看 / 调试流

    遍历元素,不改变流,多用于打印日志、调试

    nums.stream()
    .peek(n -> System.out.println("原始:" + n))
    .filter(n -> n % 2 == 0)
    .peek(n -> System.out.println("过滤后:" + n))
    .count(); // 终端触发执行

    2. 常用有状态操作(依赖全部元素 / 顺序)

    distinct 去重

    基于 equals() + hashCode() 去重

    Arrays.asList(1,2,2,3,3,3).stream()
    .distinct()
    .forEach(System.out::println);

    sorted 排序
    • 无参:自然排序(实现 Comparable)
    • 有参:自定义 Comparator 比较器

    // 自然升序
    nums.stream().sorted().forEach(System.out::println);

    // 自定义降序
    nums.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);

    limit /skip 截取 / 跳过
    • limit(n):取前 n 个元素
    • skip(n):跳过前 n 个元素

    // 跳过前2个,取后3个
    nums.stream().skip(2).limit(3).forEach(System.out::println);


    四、终端操作(Terminal)

    触发流执行,流关闭,不能继续链式调用,分为:遍历、收集、匹配、聚合、规约等。

    1. forEach /forEachOrdered 遍历

    • forEach:顺序流有序,并行流无序
    • forEachOrdered:并行流也保证遍历顺序

    nums.stream().forEach(System.out::println);
    nums.parallelStream().forEachOrdered(System.out::println);

    2. collect 收集(最核心)

    将流转回 集合、字符串、分组、分区等,Collectors 工具类提供大量静态方法。

    ① 转为 List / Set / 数组

    // 转 List
    List<Integer> list = nums.stream().collect(Collectors.toList());

    // 转 Set(自动去重)
    Set<Integer> set = nums.stream().collect(Collectors.toSet());

    // 转数组
    Integer[] array = nums.stream().toArray(Integer[]::new);

    ② 拼接字符串 joining

    List<String> strs = Arrays.asList("Java","Stream","Demo");
    // 直接拼接
    String s1 = strs.stream().collect(Collectors.joining());
    // 分隔符拼接
    String s2 = strs.stream().collect(Collectors.joining(","));
    // 分隔符 + 前缀 + 后缀
    String s3 = strs.stream().collect(Collectors.joining(",", "[", "]"));

    ③ 分组 groupingBy(类似 SQL group by)

    List<User> userList = Arrays.asList(
    new User("张三", 20),
    new User("李四", 22),
    new User("王五", 20)
    );
    // 按年龄分组 key:年龄 value:同年龄用户集合
    Map<Integer, List<User>> group = userList.stream()
    .collect(Collectors.groupingBy(User::getAge));

    ④ 分区 partitioningBy(二分区:true/false)

    只能分成两组,返回 Map<Boolean, List<T>>

    // 分区:年龄>=20 / <20
    Map<Boolean, List<User>> part = userList.stream()
    .collect(Collectors.partitioningBy(u -> u.getAge() >= 20));

    ⑤ 聚合统计(count、max、min、avg、sum)

    // 一次性统计:数量、总和、最大、最小、平均值
    IntSummaryStatistics stat = nums.stream()
    .collect(Collectors.summarizingInt(Integer::intValue));
    stat.getCount();
    stat.getSum();
    stat.getMax();

    3. 匹配操作(返回 boolean)

    // allMatch:全部满足
    boolean all = nums.stream().allMatch(n -> n > 0);

    // anyMatch:任意一个满足
    boolean any = nums.stream().anyMatch(n -> n == 3);

    // noneMatch:全部不满足
    boolean none = nums.stream().noneMatch(n -> n < 0);

    4. 查找操作

    // findFirst:获取第一个元素(顺序流稳定)
    Optional<Integer> first = nums.stream().findFirst();

    // findAny:获取任意元素(并行流效率更高)
    Optional<Integer> anyEle = nums.parallelStream().findAny();

    注意:返回 Optional,防止空指针。

    5. 规约 reduce(聚合计算,自定义累加)

    把流中元素反复结合得到一个值,常用于求和、求积、拼接。

    List<Integer> numList = Arrays.asList(1,2,3,4);

    // 1. 无初始值:返回 Optional
    Optional<Integer> sum1 = numList.stream().reduce(Integer::sum);

    // 2. 有初始值:直接返回结果(不会空)
    Integer sum2 = numList.stream().reduce(0, Integer::sum);

    // 自定义累加逻辑
    Integer total = numList.stream().reduce(0, (a, b) -> a + b * 2);


    五、数值流(IntStream / LongStream / DoubleStream)

    普通 Stream<Integer> 存在自动装箱 / 拆箱损耗,Java 提供专用数值流提升性能。

    1. 转换数值流

    List<Integer> list = Arrays.asList(1,2,3);
    // 转 IntStream
    IntStream intStream = list.stream().mapToInt(Integer::intValue);

    // 转回包装流
    Stream<Integer> stream = intStream.boxed();

    2. 范围创建数值流

    // [1,5] 闭区间
    IntStream.rangeClosed(1,5).forEach(System.out::println);

    // [1,5) 左闭右开
    IntStream.range(1,5).forEach(System.out::println);

    3. 数值便捷计算

    int sum = intStream.sum();
    int max = intStream.max().getAsInt();
    double avg = intStream.average().getAsDouble();


    六、并行流 parallelStream

    1. 开启方式

    // 方式1:集合直接调用
    list.parallelStream();

    // 方式2:顺序流转并行
    list.stream().parallel();

    2. 原理

    底层基于 Fork/Join 框架,多线程拆分任务并行执行,大数据集提升明显。

    3. 注意事项(坑)

  • 非线程安全集合不要用并行流,会并发修改异常
  • 依赖顺序的逻辑慎用并行流(findAny、forEach 会乱序)
  • 小数据量:并行流有线程开销,反而更慢
  • 不要在并行流中操作外部可变变量

  • 七、完整实战示例(传统循环 VS 流式)

    需求:过滤偶数 → 平方 → 去重 → 收集为 List

    传统 for 循环

    List<Integer> source = Arrays.asList(1,2,2,3,4,4,5);
    List<Integer> result = new ArrayList<>();
    for (Integer n : source) {
    if (n % 2 == 0) {
    int square = n * n;
    if (!result.contains(square)) {
    result.add(square);
    }
    }
    }

    Stream 流式写法(一行链式)

    List<Integer> result = source.stream()
    .filter(n -> n % 2 == 0)
    .map(n -> n * n)
    .distinct()
    .collect(Collectors.toList());


    八、常见避坑总结

  • 流只能使用一次:终端操作后流关闭,重复调用抛 IllegalStateException
  • 中间操作延迟执行:没有终端操作,中间代码完全不运行
  • 避免在流中修改原集合 / 外部变量
  • 实体类去重、比较务必重写 equals() 和 hashCode()
  • 基础类型优先用数值流,减少装箱拆箱
  • 并行流只适合无状态、不依赖顺序、大数据量场景

  • 九、Java 9+ 新增增强(拓展)

  • Stream.ofNullable():支持单个 null 元素创建流
  • takeWhile() / dropWhile():按条件截断流
  • 集合新增 stream() 重载,优化空集合场景
  • 赞(0)
    未经允许不得转载:171主机测评 » Java 流式编程(Stream)完整详解
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址