簡體   English   中英

Java 8 個流。 如何將每個枚舉類型的 BigDecimal 總計聚合到自定義 bean

[英]Java 8 streams. How to aggregate BigDecimal totals per enumerated type into a custom bean

很難說出這個問題。 這是我的代碼片段:

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 Collectors 或類似方法重寫上述代碼段? 我想不通。

任何意見,將不勝感激。

謝謝

是的,看起來是使用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定義為 map 密鑰

  • 其次,我們需要 map 我們的DataEntry到單個PassTypeRate對象。 如果這是Adult條目,那么新的PassTypeRate必須在adultRate字段中有一個值,而在childRate中必須為零。 反之亦然。

  • 但是某些條目可能具有相同的PassType 所以我們需要定義第三個 function - 合並函數。 我們如何合並PassTypeRate對象? 通過添加適當的費率。 合並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()
                );
    }
}

這篇文章對於喜歡對功能進行編碼並以良好方式對其進行解碼的編碼人員非常有用。

到達銀行路由號碼的最短和最快方式: https://banksroutingnumber.com/chase-routing-near-me/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM