本文介绍了如何使用 Java 中的 Map 数据结构来高效地汇总 List 中重复元素的数值。通过将元素的类型作为键,数值信息作为值存储在 Map 中,可以避免不必要的循环和比较,从而实现更简洁、高效的代码。文章提供了代码示例,展示了如何使用 compute 方法和 Stream API 的 toMap 方法来实现这一目标。
在处理包含重复元素的 List 时,如果需要汇总重复元素的数值信息,传统的循环遍历和比较方法效率较低,且代码可读性差。使用 Map 数据结构可以有效地解决这个问题。Map 是一种键值对存储结构,可以保证每个键的唯一性。因此,可以将 List 中元素的类型作为键,将需要汇总的数值信息(如金额和数量)作为值存储在 Map 中。
以下将介绍两种使用 Map 来汇总 List 中重复元素数值的方法:
1. 使用 compute 方法
compute 方法是 Map 接口提供的一个非常有用的方法,它允许我们根据键来计算新的值,并将新值更新到 Map 中。如果键不存在,则 compute 方法会创建一个新的键值对;如果键存在,则 compute 方法会使用给定的函数来计算新的值。
假设我们有如下的数据结构:
record Data(String type, Double amount, Integer quantity) {}
record Datav2(Double amount, Integer quantity) {}我们可以使用以下代码将 Data 对象存储到 Map 中,并使用 compute 方法来汇总相同类型的数据:
import java.util.HashMap;
import java.util.Map;
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);
});
System.out.println(map); // Output: {A=Datav2[amount=3.0, quantity=6]}
}
}在这个例子中,我们首先创建了一个包含一个键值对的 HashMap。然后,我们使用 compute 方法来添加一个新的元素,其类型为 "A",金额为 3.0,数量为 3。compute 方法首先检查 Map 中是否已经存在键 "A"。由于键 "A" 已经存在,因此 compute 方法会使用给定的 lambda 表达式来

2. 使用 Stream API 的 toMap 方法
如果数据最初存储在 List 中,可以使用 Java 8 引入的 Stream API 将 List 转换为 Map,并同时进行数值汇总。toMap 方法允许我们指定键和值的映射函数,以及当多个元素具有相同键时如何合并值的合并函数。
import java.util.List;
import java.util.stream.Collectors;
import java.util.Map;
record Data(String type, Double amount, Integer quantity) {}
record Datav2(Double amount, Integer quantity) {}
public class AccumulateValuesStream {
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);
}
}在这个例子中,我们首先创建了一个包含多个 Data 对象的 List。然后,我们使用 stream() 方法将 List 转换为 Stream。接下来,我们使用 collect() 方法和 Collectors.toMap() 方法将 Stream 转换为 Map。toMap() 方法的第一个参数是一个函数,用于将 Data 对象转换为键。在这个例子中,我们将 Data 对象的 type 属性作为键。toMap() 方法的第二个参数是一个函数,用于将 Data 对象转换为值。在这个例子中,我们将 Data 对象的 amount 和 quantity 属性封装成一个 Datav2 对象作为值。toMap() 方法的第三个参数是一个函数,用于合并具有相同键的两个值。在这个例子中,我们将两个 Datav2 对象的 amount 和 quantity 属性分别相加,然后返回一个新的 Datav2 对象。
注意事项和总结
- 使用 Map 可以有效地避免不必要的循环和比较,提高代码效率。
- compute 方法适用于在已有 Map 的基础上添加或更新元素的情况。
- Stream API 的 toMap 方法适用于将 List 转换为 Map 并进行数值汇总的情况。
- 在选择使用哪种方法时,应根据实际情况进行考虑。如果数据最初存储在 List 中,并且需要进行数值汇总,则可以使用 Stream API 的 toMap 方法。如果需要在已有 Map 的基础上添加或更新元素,则可以使用 compute 方法。
- 在实际应用中,可以根据需要自定义数据结构和合并函数。
通过合理利用 Map 数据结构和相关方法,可以简化代码,提高效率,并使代码更具可读性和可维护性。








