如何使用Java 8 Streams基于同名条件从两个列表创建映射?
使用Java Streams API实现匹配列表生成Map
嘿,我来帮你搞定这个Stream的问题!你之前用forEach的方式确实会得到void,因为forEach只是用来执行副作用(比如打印、修改外部变量),不会返回任何结果,而且这种嵌套遍历的效率也不高——每个NameAndAge都要扫一遍整个薪资列表。咱们换个更高效、更符合Stream风格的方式来做:
第一步:修正类的访问问题
首先要注意,你的NameAndSalary类中name是private修饰的,外部无法直接访问,所以得先给它添加一个getter方法,否则Stream里没法通过姓名匹配:
private class NameAndSalary { private String name; private double salary; public NameAndSalary(String name, double salary) { this.name = name; this.salary = salary; } // 添加getter方法,供外部访问name属性 public String getName() { return name; } @Override public String toString() { return name + ": " + salary; } }
NameAndAge类的name是public的,虽然能直接访问,但建议也添加getName()方法,保持代码规范。
第二步:高效生成目标Map
我们可以先把薪资列表转换成一个以姓名为键的临时Map,这样后续查找对应薪资对象的时间复杂度是O(1),然后再遍历年龄列表生成最终的Map:
import java.util.function.Function; import java.util.stream.Collectors; // 1. 先将nameAndSalaryList转换为name -> NameAndSalary的映射,快速查找 Map<String, NameAndSalary> nameToSalaryMap = nameAndSalaryList.stream() .collect(Collectors.toMap(NameAndSalary::getName, Function.identity())); // 2. 遍历nameAndAgeList,生成目标Map:键为NameAndAge,值为对应name的NameAndSalary Map<NameAndAge, NameAndSalary> resultMap = nameAndAgeList.stream() .collect(Collectors.toMap( Function.identity(), // 键就是NameAndAge对象本身 nameAndAge -> nameToSalaryMap.get(nameAndAge.name) // 根据姓名匹配对应的薪资对象 // 如果担心存在姓名不匹配的情况,可以用getOrDefault处理: // nameAndAge -> nameToSalaryMap.getOrDefault(nameAndAge.name, null) )); // 3. 按要求打印结果 resultMap.forEach((key, value) -> System.out.print("{" + key + "=" + value + "} "));
代码解释
- 第一步的临时Map:把薪资列表转成姓名到薪资对象的映射,避免了嵌套遍历,将整体时间复杂度从O(n*m)优化到O(n+m)。
Collectors.toMap:这是Stream中生成Map的核心收集器,第一个参数指定键的生成规则,第二个参数指定值的生成规则。Function.identity():是一个简写,表示“返回元素本身”,这里就是把NameAndAge对象直接作为Map的键。
运行这段代码后,就能得到你想要的输出效果:
{John: 28=John: 1000.0} {Paul: 30=Paul: 1100.0} {Adam: 31=Adam: 1200.0}
内容的提问来源于stack exchange,提问作者Ravi
相关产品推荐
相关产品推荐

