在日常开发中,我们经常需要处理对象集合的合并操作。下面记录下本人在实际开发中的一个场景,根据币种、摘要、辅助核算、科目四个属性对集合对象进行合并,并给出完整的实现方案。
一、需求场景分析
假设我们处理财务数据时,会遇到如下结构的数据集合:
List<AccountingEntry> entries = Arrays.asList(
new AccountingEntry("USD", "销售收款", "客户A", "1001", 100.0),
new AccountingEntry("USD", "销售收款", "客户A", "1001", 200.0),
new AccountingEntry("CNY", "采购付款", "供应商B", "2001", 500.0)
);
需要将相同币种、摘要、辅助核算、科目的记录合并,金额相加,得到:
[ AccountingEntry("USD", "销售收款", "客户A", "1001", 300.0), AccountingEntry("CNY", "采购付款", "供应商B", "2001", 500.0) ]
二、实现方案
1. 定义数据模型
public class AccountingEntry {
private String currency; // 币种
private String summary; // 摘要
private String auxiliaryCode; // 辅助核算
private String subjectCode; // 科目代码
private double amount; // 金额
// 构造方法/getter/setter 略
}
2. 实现合并逻辑
使用Java Stream API进行高效分组合并:
public List<AccountingEntry> mergeEntries(List<AccountingEntry> entries) {
return new ArrayList<>(entries.stream()
.collect(Collectors.toMap(
entry -> Arrays.asList(
entry.getCurrency(),
entry.getSummary(),
entry.getAuxiliaryCode(),
entry.getSubjectCode()
),
Function.identity(),
(existing, replacement) -> new AccountingEntry(
existing.getCurrency(),
existing.getSummary(),
existing.getAuxiliaryCode(),
existing.getSubjectCode(),
existing.getAmount() + replacement.getAmount()
)
))
.values());
}
3. 使用Tuple优化(可选)
对于复杂key处理,建议创建专用类:
public class CompositeKey {
private String currency;
private String summary;
private String auxiliaryCode;
private String subjectCode;
// 必须实现equals和hashCode
@Override
public boolean equals(Object o) { /*...*/ }
@Override
public int hashCode() { /*...*/ }
}
三、完整示例代码
public class AccountingMerger {
public static void main(String[] args) {
List<AccountingEntry> entries = // 初始化数据
List<AccountingEntry> merged = mergeAccountingEntries(entries);
merged.forEach(System.out::println);
}
public static List<AccountingEntry> mergeAccountingEntries(List<AccountingEntry> entries) {
return entries.stream()
.collect(Collectors.groupingBy(
entry -> new CompositeKey(
entry.getCurrency(),
entry.getSummary(),
entry.getAuxiliaryCode(),
entry.getSubjectCode()
),
Collectors.summingDouble(AccountingEntry::getAmount)
))
.entrySet().stream()
.map(entry -> new AccountingEntry(
entry.getKey().getCurrency(),
entry.getKey().getSummary(),
entry.getKey().getAuxiliaryCode(),
entry.getKey().getSubjectCode(),
entry.getValue()
))
.collect(Collectors.toList());
}
}
// 复合Key类
class CompositeKey {
// 成员变量、构造方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CompositeKey that = (CompositeKey) o;
return Objects.equals(currency, that.currency) &&
Objects.equals(summary, that.summary) &&
Objects.equals(auxiliaryCode, that.auxiliaryCode) &&
Objects.equals(subjectCode, that.subjectCode);
}
@Override
public int hashCode() {
return Objects.hash(currency, summary, auxiliaryCode, subjectCode);
}
}
四、关键点解析
- 分组策略:使用复合键(Composite Key)确保多字段的唯一性
- 金额合并:采用
Collectors.summingDouble进行数值累加 - 性能优化:时间复杂度O(n),适合大数据量处理
- 可维护性:独立CompositeKey类便于后续扩展
五、扩展思考
- 处理精度问题:建议使用BigDecimal代替double
- 并发场景:使用parallelStream()并行处理
- 空值处理:增加字段校验逻辑
六、总结
本文通过Stream API实现了高效的对象合并方案,保证了代码的简洁性和可维护性。这种模式可广泛应用于财务系统、数据分析等需要聚合计算的场景。