这个问题很难措辞。这是我的代码段:
Map<PassType, PassTypeRate> ratesPerType = new HashMap<>();
entries.stream().forEach((entry) -> {
if (!ratesPerType.containsKey(entry.getPassType())) {
ratesPerType.put(entry.getPassType(), new PassTypeRate(BigDecimal.ZERO, BigDecimal.ZERO));
}
if (AgeType.ADULT.equals(entry.getAgeType())) {
PassTypeRate passTypeRate = ratesPerType.get(entry.getPassType());
passTypeRate.setAdultRate(passTypeRate.getAdultRate().add(entry.getRate()));
}
if (AgeType.CHILD.equals(entry.getAgeType())) {
PassTypeRate passTypeRate = ratesPerType.get(entry.getPassType());
passTypeRate.setChildRate(passTypeRate.getChildRate().add(entry.getRate()));
}
});
因此,
entries
是包含ageType,passType和rate的bean列表。我需要汇总每个“ ageType”和“ passType”的总费用。PassTypeRate Bean包含每个“ PassType”的成人或儿童费用总计。
我的基本问题是...。是否可以使用Java 8 Collector或类似工具重写以上代码段?我不知道。
任何意见,将不胜感激。
谢谢
最佳答案
是的,看起来很适合用Collectors.toMap
实施。看一下下面的实现(我使用lombok(https://projectlombok.org/)使其更具可读性):
Map<PassType, PassTypeRate> group(List<DataEntry> entries) {
return entries.stream()
.collect(Collectors.toMap(
DataEntry::getPassType,
entry -> PassTypeRate.builder()
.adultRate(entry.getAgeType() == ADULT ? entry.getRate() : BigDecimal.ZERO)
.childRate(entry.getAgeType() == CHILD ? entry.getRate() : BigDecimal.ZERO)
.build(),
(rate1, rate2) -> PassTypeRate.builder()
.childRate(rate1.getChildRate().add(rate2.getChildRate()))
.adultRate(rate1.getAdultRate().add(rate2.getAdultRate()))
.build()
));
}
简短说明:
首先,我们需要定义
PassType
作为映射键其次,我们需要将
DataEntry
映射到单个PassTypeRate
对象。如果这是Adult
条目,则新的PassTypeRate
必须在adultRate
字段中具有值,在childRate
中为零。反之亦然。但是某些条目可能具有相同的
PassType
!因此,我们需要定义第三个功能-合并功能。我们如何合并PassTypeRate
对象?通过添加适当的费率。由于添加了两个PassTypeRate
对象,因此合并功能返回新的PassTypeRate
。我还准备了一些测试用例,以验证解决方案是否有效-似乎可行:)以下测试用例:
public class RateGroupingTest {
private RateGrouping subject = new RateGrouping();
@Test
public void groups() {
//given
List<DataEntry> entries = List.of(
new DataEntry(ADULT, X, new BigDecimal("3")),
new DataEntry(ADULT, Y, new BigDecimal("5")),
new DataEntry(ADULT, Z, new BigDecimal("7")),
new DataEntry(CHILD, X, new BigDecimal("11")),
new DataEntry(CHILD, Y, new BigDecimal("13")),
new DataEntry(CHILD, Z, new BigDecimal("17")),
new DataEntry(ADULT, X, new BigDecimal("13")),
new DataEntry(ADULT, Y, new BigDecimal("25")),
new DataEntry(ADULT, Z, new BigDecimal("37")),
new DataEntry(CHILD, X, new BigDecimal("411")),
new DataEntry(CHILD, Y, new BigDecimal("513")),
new DataEntry(CHILD, Z, new BigDecimal("617"))
);
//when
Map<PassType, PassTypeRate> actual = subject.group(entries);
//then
assertThat(actual.get(PassType.X))
.isEqualTo(
PassTypeRate.builder()
.childRate(new BigDecimal("422"))
.adultRate(new BigDecimal("16"))
.build()
);
assertThat(actual.get(PassType.Y))
.isEqualTo(
PassTypeRate.builder()
.childRate(new BigDecimal("526"))
.adultRate(new BigDecimal("30"))
.build()
);
assertThat(actual.get(PassType.Z))
.isEqualTo(
PassTypeRate.builder()
.childRate(new BigDecimal("634"))
.adultRate(new BigDecimal("44"))
.build()
);
}
}