You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Java8 Stream从两个Student列表提取目标元素并计算薪资差

实现方案

核心筛选规则

最终结果集需要覆盖两类元素:

  • 列表A中存在,但在列表B中按no+age+city三个字段完全匹配不到的对象
  • 列表A和B能按上述三个字段匹配到,但薪资值不相等的对象;这类对象需要保留A侧的基础字段,将薪资值替换为「A的薪资 - B的薪资」的差值;三字段匹配但薪资相等的对象直接排除。

现有代码的逻辑缺陷

当前代码通过anyMatch筛选的规则是「只要A的元素能在B中按三个字段匹配到就保留」,完全没有覆盖两类筛选场景:

  • 没有保留A存在但B完全匹配不到的元素
  • 没有处理「三字段匹配但薪资不同时,替换为薪资差值」的逻辑
    如果直接把anyMatch换成noneMatch,又会漏掉「三字段匹配但薪资不同」的第二类元素,筛选范围覆盖不全。
    另外逐元素遍历A时全量扫描B列表做匹配的写法,时间复杂度为O(n*m),数据量较大时性能表现很差。

可落地的Java8 Stream实现

为了避免重复扫描B列表,先提前把B列表按匹配字段做索引映射,后续查找时可以直接通过键值匹配,时间复杂度优化为O(n+m):

// 1. 构建B列表的匹配索引:key为no+age+city拼接的唯一匹配键,value为对应的B侧Student对象
Map<String, Student> bIndex = B.stream()
        .collect(Collectors.toMap(
                stu -> buildMatchKey(stu.getNo(), stu.getAge(), stu.getCity()),
                Function.identity(),
                // 若B中存在同匹配键的重复元素,默认保留第一个出现的对象
                (oldStu, newStu) -> oldStu
        ));

// 2. 遍历A列表筛选符合要求的结果
List<Student> resultSet = A.stream()
        .map(aStu -> {
            String matchKey = buildMatchKey(aStu.getNo(), aStu.getAge(), aStu.getCity());
            Student matchedBStu = bIndex.get(matchKey);
            // 场景1:B中无匹配项,直接返回原A对象
            if (matchedBStu == null) {
                return aStu;
            }
            // 场景2:B中有匹配项,对比薪资值
            // 薪资相等则不符合要求,返回null后续统一过滤
            if (aStu.getSalary().equals(matchedBStu.getSalary())) {
                return null;
            }
            // 薪资不等则构造新对象,替换薪资为差值
            return new Student(
                    aStu.getNo(),
                    aStu.getAge(),
                    aStu.getCity(),
                    aStu.getBirthDate(),
                    aStu.getSalary() - matchedBStu.getSalary()
            );
        })
        // 过滤掉薪资相等返回null的无效元素
        .filter(Objects::nonNull)
        .collect(Collectors.toList());

// 抽取的匹配键构造方法
private static String buildMatchKey(String no, Integer age, String city) {
    return no + "_" + age + "_" + city;
}

效果验证

代入你给出的测试数据走查逻辑:

  • A中no=2的Dublin学生、no=5的London学生:在B的匹配索引中找不到对应键值,直接纳入结果集
  • A中no=1的Rome学生:匹配到B中同三字段的对象,A薪资300、B薪资700,计算得差值-400,纳入结果集
  • A中no=3的Istanbul学生:匹配到B中同三字段的对象,两边薪资均为350,直接过滤不纳入
  • A中no=4的Madrid学生:匹配到B中同三字段的对象,两边薪资均为450,直接过滤不纳入
    最终输出的结果集和你给出的示例完全一致。

注意:如果数据量极小不想提前建索引,也可以直接在流中嵌套两层匹配实现,但不推荐,嵌套扫描的写法性能随列表长度增长下降很快。


内容的提问来源于stack exchange,提问作者tom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.31 16:36:03