0

Its not real code, but an analogy to my exact scenario. Main concern here is the util stream pipeline.

Lets assume, I've following object model

    @Data
    class ItemRequest {
       String action;
       List<ItemId> itemIds;
    }
    @Data
    class ItemId{
       ItemType itemType;
       long itemKey;
    }
    @Getter 
    @AllArgsConstructor
    enum ItemType{

      String backingService;
      String description; 

      ITEM_TYPE_1("backingService1","type 1 description"),
      ITEM_TYPE_2("backingService1","type 2 description"),
      ITEM_TYPE_3("backingService2","type 3 description"),
      ITEM_TYPE_4("backingService2","type 4 description"),
      ITEM_TYPE_5("backingService2","type 5 description"),
      ITEM_TYPE_6("backingService3","type 6 description"),
      ITEM_TYPE_7("backingService3","type 7 description"),
     //   so on
    }

Now each ItemType has a different backend microservice. My ItemType enum has getters to return backing service. So I want to break down my ItemRequest by backing service.

I can easily do it in imperative way or running 2 stream pipeline. But I want to use it in one stream pipeline

For Example, in simple terms, my question is How to combine following 2 steps I wrote below into one pipeline .

Map<String,ItemRequest> breakItemRequestAsPerBackingService
 (ItemRequest originalItemRequest ){
    Map<String, List<ItemId>> collect
     = originalItemRequest
               .getItemIds()
               .stream()
               .collect(Collectors.groupingBy(
                     e -> e.getItemType().getBackingService()));



    return collect 
    .entrySet()
    .stream()
    .collect(toMap(
             Map.Entry::getKey,
              e -> new ItemRequest(
                     originalItemRequest.getAction(), 
                     e.getValue())));
}
ThrowableException
  • 1,168
  • 1
  • 8
  • 29

1 Answers1

1

Your second operation

collect.entrySet().stream()
    .collect(toMap(
        Map.Entry::getKey,
        e -> new ItemRequest(originalItemRequest.getAction(), e.getValue())));

is keeping the result key of the previous operation and only applying a function to the values. You can apply a function to the result of a previous Collector using collectingAndThen. To use it with groupingBy for the map values, you have to realize that groupingBy(f) is a short-hand for groupingBy(f, toList()), so toList() is the collector to combine with collectingAndThen.

Map<String,ItemRequest>
    breakItemRequestAsPerBackingService(ItemRequest originalItemRequest) {

    return originalItemRequest.getItemIds().stream()
        .collect(Collectors.groupingBy(e -> e.getItemType().getBackingService(),
            Collectors.collectingAndThen(Collectors.toList(),
                list -> new ItemRequest(originalItemRequest.getAction(), list))
        ));
}
Holger
  • 285,553
  • 42
  • 434
  • 765