本文介绍了如何使用 Java map 结构有效地聚合 List 中具有相同类型(Type)的元素的数值,例如金额(Amount)和数量(Quantity)。通过将 List 转换为 Map,并利用 compute 方法或 Stream API 的 toMap 操作,可以避免手动循环和比较,从而简化代码并提高效率。本教程提供了详细的代码示例,展示了如何创建、更新和合并 Map 中的数据,最终得到聚合后的结果。
在处理包含重复元素的 List 时,如果需要对特定字段进行聚合操作,使用 Map 是一种非常有效的方法。Map 允许我们以键值对的形式存储数据,其中键是唯一的,这使得我们可以方便地根据键(例如,元素的类型)来累加相关的值(例如,金额和数量)。
使用 Map 的 compute 方法
如果已经有一个 Map,并且需要向其中添加或更新元素,可以使用 compute 方法。该方法接受一个键和一个 Bifunction 作为参数。BiFunction 接受键和当前值(如果存在)作为输入,并返回新的值。如果键不存在,则当前值为 NULL。
以下示例展示了如何使用 compute 方法向 Map 中添加元素,并累加金额和数量:
立即学习“Java免费学习笔记(深入)”;
import java.util.HashMap; import java.util.Map; record Datav2(Double amount, Integer quantity) {} public class AccumulateValues { public static void main(String[] args) { var map = new HashMap<>(Map.of("A", new Datav2(2.0, 3))); // add element to map equivalent to Data("A", 3.0, 3) map.compute("A", (k, v) -> { if (v == null) { v = new Datav2(0.0, 0); } return new Datav2(3.0, v.quantity() + 3); // Corrected: Use 3.0 instead of v.amount = 3.0 }); System.out.println(map); // Output: {A=Datav2[amount=3.0, quantity=6]} } }
注意事项:
- compute 方法中的 BiFunction 必须返回新的值,而不是直接修改当前值。
- 如果键不存在,BiFunction 应该返回一个新创建的对象。
- 上述代码已经修正,直接返回新的 Datav2 对象,避免了直接修改 v.amount 的问题。
使用 Stream API 的 toMap 方法
如果需要将一个 List 转换为 Map,可以使用 Stream API 的 toMap 方法。该方法接受三个参数:
- keyMapper: 用于生成键的 Function。
- valueMapper: 用于生成值的 Function。
- mergeFunction: 用于合并具有相同键的两个值的 BinaryOperator。
以下示例展示了如何使用 toMap 方法将 List 转换为 Map,并累加金额和数量:
import java.util.List; import java.util.stream.Collectors; record Data(String type, Double amount, Integer quantity) {} public class AccumulateValuesFromList { public static void main(String[] args) { var list = List.of(new Data("A", 2.0, 3), new Data("A", 3.0, 3), new Data("C", 2.0, 1), new Data("B", 10.0, 3), new Data("B", 2.0, 5)); var collected = list .stream() .collect(Collectors.toMap( // what will the key be Data::type, // what will the value be data -> new Datav2(data.amount, data.quantity), // how do we combine two values if they have the same key (d1, d2) -> new Datav2(d1.amount() + d2.amount(), d1.quantity() + d2.quantity()) )); System.out.println(collected); // Output: {A=Datav2[amount=5.0, quantity=6], B=Datav2[amount=12.0, quantity=8], C=Datav2[amount=2.0, quantity=1]} } }
注意事项:
- keyMapper 必须返回唯一的键。如果存在重复的键,则会抛出 IllegalStateException 异常。可以使用 mergeFunction 来处理重复的键。
- mergeFunction 必须返回合并后的值。
总结
使用 Map 可以有效地聚合 List 中重复元素的数值。compute 方法适用于向已有的 Map 中添加或更新元素,而 toMap 方法适用于将 List 转换为 Map。选择哪种方法取决于具体的需求和场景。通过合理使用 Map,可以简化代码并提高效率。