问题解决:基于ID合并两个列表并计算quantity差值
定义的类 @AllArgsConstructor
@Getter
@Setter
public static class Manipulate {
private int id;
private int quantity;
}
待处理的两个列表 List<Manipulate> a = new ArrayList<>();
a.add(new Manipulate(1,100));
a.add(new Manipulate(2,200));
List<Manipulate> b = new ArrayList<>();
b.add(new Manipulate(1,10));
b.add(new Manipulate(2,20));
需求 基于id属性匹配两个列表,将a中对象的quantity减去b中对应ID对象的quantity,结果存入新列表。
尝试的代码 List<Manipulate> c = a.stream().map(k -> {
b.stream().filter(j -> j.getId() == k.getId())
.forEach(i -> {
int i1 = k.getQuantity() - i.getQuantity();
k.setQuantity(i1);
});
return k;
});
编译错误(中文翻译) 所需类型:List
提供的类型:Stream
不存在类型变量R的实例,使得Stream可以转换为List
问题分析与解决方案 1. 报错原因 stream().map()方法返回的是Stream<Manipulate>类型,不能直接赋值给List<Manipulate>变量,必须调用collect(Collectors.toList())将流转换为列表。
2. 优化后的代码(推荐) 直接修改原列表a的对象会污染原数据,且每次遍历a都去遍历b效率低下(时间复杂度O(n*m))。推荐先将b转换为以id为键的Map,再进行计算,同时创建新对象保存结果:
// 将列表b转换为id到quantity的映射,提升查找效率
Map<Integer, Integer> bQuantityMap = b.stream()
.collect(Collectors.toMap(Manipulate::getId, Manipulate::getQuantity));
// 生成结果列表,不修改原数据
List<Manipulate> c = a.stream()
.map(manipulate -> {
// 若b中无对应id,默认减去0
int subtractAmount = bQuantityMap.getOrDefault(manipulate.getId(), 0);
return new Manipulate(manipulate.getId(), manipulate.getQuantity() - subtractAmount);
})
.collect(Collectors.toList());
3. 修正原代码(不推荐,会修改原数据) 如果一定要沿用原逻辑,只需添加collect步骤即可解决编译错误:
List<Manipulate> c = a.stream().map(k -> {
b.stream().filter(j -> j.getId() == k.getId())
.forEach(i -> {
int i1 = k.getQuantity() - i.getQuantity();
k.setQuantity(i1);
});
return k;
}).collect(Collectors.toList()); // 新增流转列表的操作
内容的提问来源于stack exchange,提问作者sathish kumar