title: Java 8 grouping into collection of objects
body: <p>I would like to group a collection of Rental objects on the due date but I want to create a new RentalReport object for each group with the key as a predefined value (enum) and the group to be a property on that object. I have achieved this by fitering the collection on each criteria and creating a RentalReport object for each but I was wondering if this can be done using the groupingBy method of the Collectors class. </p>
  
  <p>Is it possible to group by a predefined set of filters in java 8 so I could create a map where the key is the enum and the value is the collection of Rental objects. Then I could iterate over this map and generate the RentalReport objects.</p>
  
  <p>I have created this demo but the real task involves multiple group by clauses so would be great if I can achieve this by grouping. </p>
  
  <pre><code>    import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.List;
  import java.util.stream.Collectors;
  import org.joda.time.DateTime;
  
  public class TestGrouping {
  
      enum RentalClassification {
          UNRESTRICTED, //No restriction restricted=false
          OVERDUE,      //todays date after due date.
          NEARLY_OVERDUE, // todays date after due date + 2 days
          NOT_OVERDUE
      }
  
      public static void main(String[] args) {
  
          class Rental {
              Integer rentalId;
              Integer productId;
              boolean restricted;
              DateTime dueDate;
  
              public Rental(Integer rentalId, Integer productId, boolean restricted, DateTime dueDate){
                  this.rentalId = rentalId;
                  this.productId = productId;
                  this.restricted = restricted;
                  this.dueDate = dueDate;
              }
  
              public Integer getRentalId() {
                  return rentalId;
              }
  
              public void setRentalId(Integer rentalId) {
                  this.rentalId = rentalId;
              }
  
              public Integer getProductId() {
                  return productId;
              }
  
              public void setProductId(Integer productId) {
                  this.productId = productId;
              }
  
              public boolean isRestricted() {
                  return restricted;
              }
  
              public void setRestricted(boolean restricted) {
                  this.restricted = restricted;
              }
  
              public DateTime getDueDate() {
                  return dueDate;
              }
  
              public void setDueDate(DateTime dueDate) {
                  this.dueDate = dueDate;
              }
  
              public String toString(){
                  return "RentalId:"+this.rentalId+". ProductId:"+this.productId+". Due date:"+this.dueDate+". -";
              }
          }
  
          class RentalReport {
  
              RentalClassification classification;
              List&lt;Rental&gt; rentals;
  
              public RentalReport(RentalClassification classification, List&lt;Rental&gt; rentals) {
                  this.classification = classification;
                  this.rentals = rentals;
              }
  
              public RentalClassification getClassification() {
                  return classification;
              }
              public void setClassification(RentalClassification classification) {
                  this.classification = classification;
              }
              public List&lt;Rental&gt; getRentals() {
                  return rentals;
              }
              public void setRentals(List&lt;Rental&gt; rentals) {
                  this.rentals = rentals;
              }
  
              public String toString(){
                  StringBuilder sb = new StringBuilder("Classification:"+this.classification.name()+". Rental Ids:");
                  this.rentals.forEach(r -&gt; sb.append(r.getRentalId()));
                  return sb.toString();
  
              }
  
          }
  
          DateTime today = new DateTime();
  
          List&lt;Rental&gt; rentals = Arrays.asList(
                  new Rental(1,100, true, today.plusDays(-10)),
                  new Rental(2,101, false, today.plusDays(-10)),
                  new Rental(3,102, true, today.plusDays(-4)),
                  new Rental(4,103, true, today.plusDays(-4)),
                  new Rental(5,104, true, today.plusDays(-4)),
                  new Rental(6,105, true, today.plusDays(2)),
                  new Rental(7,106, true, today.plusDays(2)),
                  new Rental(8,107, true, today.plusDays(2)),
                  new Rental(9,108, true, today.plusDays(4)),
                  new Rental(10,109, true, today.plusDays(5))
                  );
  
  
          List&lt;RentalReport&gt; rentalReports = new ArrayList&lt;RentalReport&gt;();
  
          List&lt;Rental&gt; unrestrictedRentals = rentals.stream()
                                             .filter(r -&gt; !r.isRestricted())
                                             .collect(Collectors.toList());
  
          rentalReports.add(new RentalReport(RentalClassification.UNRESTRICTED, unrestrictedRentals));
  
          List&lt;Rental&gt; overdueRentals = rentals.stream()
                                        .filter(r -&gt; r.isRestricted() &amp;&amp; r.getDueDate().isBefore(new DateTime()))
                                        .collect(Collectors.toList());
  
          rentalReports.add(new RentalReport(RentalClassification.OVERDUE, overdueRentals));
  
          List&lt;Rental&gt; nearlyOverdueRentals = rentals.stream()
                                              .filter(r -&gt; r.isRestricted() 
                                                      &amp;&amp; r.getDueDate().isAfter(new DateTime())
                                                      &amp;&amp; r.getDueDate().isBefore(new DateTime().plusDays(2)))
                                              .collect(Collectors.toList());
  
          rentalReports.add(new RentalReport(RentalClassification.NEARLY_OVERDUE, nearlyOverdueRentals));
  
          List&lt;Rental&gt; notOverdueRentals = rentals.stream()
                                          .filter(r -&gt; r.isRestricted() &amp;&amp; r.getDueDate().isAfter(new DateTime()))
                                          .collect(Collectors.toList());
  
          rentalReports.add(new RentalReport(RentalClassification.NOT_OVERDUE, notOverdueRentals));
  
          System.out.println("Rental Reports: "+rentalReports.toString());
  
      }
      }
  </code></pre>