这个问题很难措辞。这是我的代码段:

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()
                );
    }
}

09-26 03:06