GroupingBy with List as a result

Viewed 168

We have the following:

public List<Balance> mapToBalancesWithSumAmounts(List<MonthlyBalancedBooking> entries) {
    return entries
      .stream()
      .collect(
        groupingBy(
          MonthlyBalancedBooking::getValidFor,
          summingDouble(MonthlyBalancedBooking::getAmount)
        )
      )
      .entrySet()
      .stream()
      .map(localDateDoubleEntry -> new Balance(localDateDoubleEntry.getValue(), localDateDoubleEntry.getKey()))
      .collect(toList());
  }

Is there a possibility to avoid the second stream() path in the code, so the result of the groupingBy() should be a list in our case. We need a possibility to pass the map()-function to collect or groupingBy is that possible in Java 8?

2 Answers

The simple way is just using toMap() collector with merge function like this:

List<Balance> balances = new ArrayList<>(entries.stream()
       .collect(toMap(MonthlyBalancedBooking::getValidFor, m -> new Balance(m.getAmount(),
                                              m.getValidFor()),Balance::merge)).values());

I supposed for Balance class these properties:

class Balance {
   private Double value;
   private Integer key;

   public Balance merge(Balance b) {
     this.value += b.getValue();
     return this;
   }
}

That wouldn't be possible since the value that you are looking for as you map to the Balance objects could only be evaluated once all the entries of the MonthlyBalancedBooking list are iterated.

new Balance(localDateDoubleEntry.getValue(), localDateDoubleEntry.getKey())

An alternate way though with moving the stream though within a single terminal operation could be by using collectingAndThen as:

public List<Balance> mapToBalancesWithSumAmounts(List<MonthlyBalancedBooking> entries) {
    return entries.stream()
            .collect(Collectors.collectingAndThen(
                    Collectors.groupingBy(MonthlyBalancedBooking::getValidFor,
                            Collectors.summingDouble(MonthlyBalancedBooking::getAmount)),
                    map -> map.entrySet().stream()
                            .map(entry -> new Balance(entry.getValue(), entry.getKey()))))
            .collect(Collectors.toList());
}
Related