如何将含内部迭代器的增强for循环转换为Stream并实现值求和?
用Stream实现按月累加里程费用的正确姿势
嘿,你的思路已经走对大半啦!问题就卡在Collectors.toMap的第三个合并函数上——你现在写的(k1, k2) -> k1只是保留了第一个遇到的值,但我们需要的是把相同月份的数值累加起来。
完整的Stream解决方案
Map<Month, Integer> data = scooters.stream() .flatMap(scooter -> scooter.getRentalDays().stream() .map(date -> Map.entry(date.getMonth(), scooter.getMileage() * scooter.getMileageRate()))) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, // 把重复key的新旧值相加,替换原来的保留第一个值的逻辑 (existingVal, newVal) -> existingVal + newVal ));
来拆解一下这段代码的逻辑:
- 第一步
scooters.stream():把你的scooter集合转换成Stream,开启链式操作。 - 第二步
flatMap(...):每个scooter对应多个租赁日期,用flatMap把每个日期转成一个(月份, 该scooter的里程费用)的Entry,这样所有scooter的所有日期Entry会被平铺成一个统一的流。 - 第三步
collect(Collectors.toMap(...)):- 第一个参数
Map.Entry::getKey:指定用Entry里的月份作为最终Map的key。 - 第二个参数
Map.Entry::getValue:指定用Entry里的里程费用作为初始value。 - 第三个参数就是你之前没写对的地方——当遇到同一个月份的key时,把已有的值和新进来的值相加,这样就实现了按月累加的效果。
- 第一个参数
还有一种更直观的写法(可选)
如果你觉得用Map.entry有点绕,也可以用groupingBy配合summingInt,语义上更贴近“按月份分组求和”的需求,可读性可能更好:
Map<Month, Integer> data = scooters.stream() .flatMap(scooter -> scooter.getRentalDays().stream() .map(date -> new AbstractMap.SimpleEntry<>(date.getMonth(), scooter.getMileage() * scooter.getMileageRate()))) .collect(Collectors.groupingBy( Map.Entry::getKey, Collectors.summingInt(Map.Entry::getValue) ));
这里先按月份分组,再对每组里的所有里程费用求和,逻辑一目了然。
内容的提问来源于stack exchange,提问作者Richard Avalos
相关产品推荐
相关产品推荐

