1. 概述

在 Java Stream 开发中,高效处理和转换数据是写出优质代码的关键。处理连续元素时,使用 SimpleEntry 进行简单配对和利用有状态转换处理动态场景,是两种强有力的技术。

本教程将探讨如何利用 SimpleEntry 创建相邻元素对,以及有状态转换如何提供灵活的数据流处理方案。让我们深入探索这些方法如何优化 Java Stream 操作。

2. 问题定义

给定一个元素流,我们需要创建一个包含连续元素对的列表。例如,对于整数流 *[1, 2, 3, 4, 5]*,期望输出配对结果 *[(1, 2), (2, 3), (3, 4), (4, 5)]*。

接下来看具体实现方案。

3. 解决方案

根据不同需求和约束条件,收集流中连续元素对有多种实现方式。这里介绍两种常用方法:

3.1. 收集为 List

核心思路是先将流元素收集到列表中,通过索引访问实现配对操作。 这种方法简单直接,适合大多数场景。

public static <T> List<SimpleEntry<T, T>> collectSuccessivePairs(Stream<T> stream) {
    List<T> list = stream.collect(Collectors.toList());
    return IntStream.range(0, list.size() - 1)
      .mapToObj(i -> new SimpleEntry<>(list.get(i), list.get(i + 1))).collect(Collectors.toList());
}

实现要点:

  1. ✅ 使用 Collectors.toList() 将流元素转为列表
  2. ✅ 通过 IntStream.range(0, list.size() - 1) 生成有效索引(注意排除末尾元素)
  3. ✅ 用 SimpleEntry 包装相邻元素对
  4. ✅ 最终收集为新列表

时间复杂度分析:

  • 流转列表:O(n)
  • 元素配对:O(n)
  • 总体时间复杂度:O(n)

空间复杂度分析:

  • 元素存储:O(n)
  • 结果列表:O(n)
  • 总体空间复杂度:O(n)

3.2. 收集为 List<List>

这种方法将连续元素对存储为嵌套列表结构,适合需要灵活处理元素对的场景:

public static <T> Stream<List<T>> pairwise(Stream<T> stream) {
    List<T> list = stream.collect(Collectors.toList());
    List<List<T>> pairs = new ArrayList<>();
    for (int i = 0; i < list.size() - 1; i++) {
        pairs.add(Arrays.asList(list.get(i), list.get(i + 1)));
    }
    return pairs.stream();
}

关键步骤:

  1. ✅ 流元素收集到列表(保证随机访问)
  2. ✅ 循环遍历到倒数第二个元素
  3. ✅ 用 Arrays.asList() 创建相邻元素对
  4. ✅ 返回新流(支持后续链式操作)

⚠️ 注意:此方法返回的是 Stream<List<T>> 而非直接列表,保留了流操作的灵活性。

复杂度分析:

  • 时间复杂度:O(n)(收集+配对)
  • 空间复杂度:O(n)(元素存储+结果存储)
  • 与 SimpleEntry 方案复杂度相同,但数据结构更灵活

4. 总结

本文探讨了在 Java Stream 中处理连续元素对的两种核心方法:

  • SimpleEntry 方案:简洁高效,适合固定配对场景
  • List<List> 方案:灵活可扩展,适合复杂处理流程

两种方法各有优势:

  • ✅ 时间复杂度均为 O(n)
  • ✅ 空间复杂度均为 O(n)
  • ✅ 实现简单直观
  • ⚠️ 需注意中间存储开销(不适合超大流)

实际开发中,根据具体需求选择即可。对于简单配对场景,SimpleEntry 更轻量;需要后续流操作时,List<List> 方案更灵活。

所有示例代码已上传至 GitHub 仓库,欢迎参考实践。


原始标题:Collect Successive Pairs From a Stream in Java | Baeldung