使用Java流API

时间:2019-03-13 09:36:48

标签: java java-stream

我从数据库收到一些结果集,并将每一行存储为DbRow类型的对象,这是该类:

public class DbRow {

    private int clientNumber;
    private String recordNumber;
    private String takeoverMonth;
    private int takeovers;
    private int mainClaims;
    private int distinctContractDates;
    private LocalDate contractDate;

    public DbRow(int clientNumber, String recordNumber, String takeoverMonth, int takeovers,
                int mainClaims, int distinctContractDates, LocalDate contractDate) {
        super();
        this.clientNumber = clientNumber;
        this.recordNumber = recordNumber;
        this.takeoverMonth = takeoverMonth;
        this.takeovers = takeovers;
        this.mainClaims = mainClaims;
        this.distinctContractDates = distinctContractDates;
        this.contractDate = contractDate;
    }

    // getters & setters

    // hashCode, equals & toString
}

我目前将接收到的对象存储在Map<Integer, List<DbRow>>中,以使它们由某个属性分开(在本例中为clientNumber,所有DbRow具有特定的客户编号)存储在List<DbRow>>中,而其密钥是此特定客户号。

我需要在其中创建一个Map<Integer, Map<String, Map<LocalDate, Integer>>>,我目前使用很多代码行。

所需结果可描述为
每个客户月每个接管月的不同合同日期计数
(例如Map<客户编号, Map<收购月份, Map<合同日期,数量>>>
接管月份为String格式的"yyyy/MM"

我当前的解决方案很丑陋,但是可行。它包含子图的创建和填充,以及检查我想摆脱的现有键。请看看:

Map<Integer, List<DbRow>> records = new TreeMap<>();

// fill records with database results ...

Map<Integer, Map<String, Map<LocalDate, Integer>>> results = new TreeMap<>();

records.forEach((clientNumber, dbRows) -> {
    Map<String, List<DbRow>> rowsPerMonth = dbRows.stream()
                    .collect(Collectors.groupingBy(DbRow::getTakeoverMonth));
    Map<String, Map<LocalDate, Integer>> monthResults = new TreeMap<>();

    rowsPerMonth.forEach((takeoverMonth, rows) -> {
        if (monthResults.containsKey(takeoverMonth)) {
            Map<LocalDate, Integer> contractDateCount = monthResults.get(takeoverMonth);
            rows.forEach(dbRow -> {
                LocalDate contractDate = dbRow.getContractDate();
                if (contractDateCount.containsKey(contractDate)) {
                    int count = contractDateCount.get(contractDate);
                    count++;
                    contractDateCount.put(contractDate, count);
                } else {
                    contractDateCount.put(contractDate, 1);
                }
            });
            monthResults.put(takeoverMonth, contractDateCount);
        } else {
            Map<LocalDate, Integer> contractDateCount = new TreeMap<>();
            rows.forEach(dbRow -> {
                LocalDate contractDate = dbRow.getContractDate();
                if (contractDateCount.containsKey(contractDate)) {
                    int count = contractDateCount.get(contractDate);
                    count++;
                    contractDateCount.put(contractDate, count);
                } else {
                    contractDateCount.put(contractDate, 1);
                }
            });
            monthResults.put(takeoverMonth, contractDateCount);
        }
    });

    results.put(clientNumber, monthResults);
});

有人知道(如果有)使用流API以更短的方式做到这一点的方法吗?我真的很想为此提供解决方案。

1 个答案:

答案 0 :(得分:2)

您可能会寻找类似的东西:

Map<Integer, Map<String, Map<LocalDate, Long>>>  countDistinctDatesPerMonthPerClient(List<DbRow> input) {
    return input.stream()
            .collect(Collectors.groupingBy(DbRow::getClientNumber,
                    Collectors.groupingBy(DbRow::getTakeoverMonth,
                            Collectors.groupingBy(DbRow::getContractDate, Collectors.counting()))));
}