Java 8 - 如何使用带有 groupingBy 和 summingInt 的 lambda 并使用按位运算符

Java 8 - how to work with lambda with groupingBy and summingInt and use Bitwise operator

我有自己的 class,名为 CheckIn,属性 dayStringworkingHoursintinProgress 作为 boolean:

public class CheckIn {
    public int id;
    public String day;
    public int workingHours;
    public boolean inProgress;

    public CheckIn(String day, in hours, boolean inProgress) {
        this.day = day;
        this.workingHours = hours;
        this.inProgress = inProgress;
    }
}

我的系统中有条目列表,我需要这些条目的摘要并将它们按天分组,然后对工作时间求和。在这里没问题,我可以使用 lambda 来实现它,但是如果我想设置进度为真,如果有任何条目是真的?

// Suppose this is the inputs 
List<CheckIn> checkinsList = new ArrayList<>();
checkinsList.add(new CheckIn("26-11-2015",6,true));
checkinsList.add(new CheckIn("27-11-2015",6,false));
checkinsList.add(new CheckIn("26-11-2015",6,false));
checkinsList.add(new CheckIn("27-11-2015",4,false));
checkinsList.add(new CheckIn("26-11-2015",1,false));
checkinsList.add(new CheckIn("28-11-2015",6,false));
checkinsList.add(new CheckIn("28-11-2015",6,false));
checkinsList.add(new CheckIn("28-11-2015",6,true));


List<CheckIn> summary = new ArrayList<>();

checkinsList.stream().collect(Collectors.groupingBy(Function.identity(),
    () -> new TreeMap<>(
        Comparator.<CheckIn, String>comparing(entry -> entry.day)),
        Collectors.summingInt(entry -> entry.duration))).forEach((e, sumTargetDuration) -> {
        CheckIn entry = new CheckIn();
        entry.day = e.day;
        entry.duration = sumTargetDuration;
        // Here my something like what I need?
        entry.inProgress = e.inProgress;
        summary.add(entry);
});

我需要 summary 列表包含(在本例中用于输入)在这 3 天内有 3 个项目:

我想要这样的结果:

我希望摘要带有 inProgress true 如果那天有任何条目 inProgress == true 它适用于 lambda 吗?

您需要为此任务构建自定义收集器。问题是没有内置的收集器可以将多个收集器组合在一起并应用整理操作。在这种情况下,我们需要组合 3 个收集器:summingIntreducing,每个 ors inProgress,以及 mapping,映射到那天。

下面class会在采集过程中持有汇总,并据此计算结果。我们可以添加关于当天的额外检查,因为它在整个过程中应该是相同的,但为了简单起见,我将这些排除在外。

public class CheckInSummary {

    private int workingHours;
    private boolean inProgress;
    private String day;

    public void accept(CheckIn checkIn) {
        workingHours += checkIn.workingHours;
        inProgress = inProgress || checkIn.inProgress;
        day = checkIn.day;
    }

    public CheckInSummary combine(CheckInSummary summary) {
        workingHours += summary.workingHours;
        inProgress = inProgress || summary.inProgress;
        return this;
    }

    public CheckIn finish() {
        return new CheckIn(day, workingHours, inProgress);
    }

}

然后,您可以从这个 class 使用以下方法创建一个收集器:

private static Collector<CheckIn, ?, CheckIn> summary() {
    return Collector.of(
                CheckInSummary::new,
                CheckInSummary::accept,
                CheckInSummary::combine,
                CheckInSummary::finish
           );
}

你终于可以像这样使用它了:

List<CheckIn> result = 
      new ArrayList<>(checkinsList.stream()
                                  .collect(groupingBy(c -> c.day, summary()))
                                  .values());

测试用例的输出:

[[27-11-2015, 10, false], [26-11-2015, 13, true], [28-11-2015, 18, true]]

这个列表没有排序,但如果你想排序,你只需要额外调用 sort() 比较日期。