Java собирает с группировкой и отображением для `set`, но нуждается в пустом наборе, если все значения равны` null` - PullRequest
0 голосов
/ 10 января 2019

В моем приложении Java 11 я хочу получать обновления продуктов из репозитория. В одном обновлении продукта есть updateId и список productIds для обновления.

  • Если нет номеров продуктов, которые необходимо обновить для обновления с помощью updateId = X, я все еще хочу записать в другую таблицу, в которой обработано обновление X; updateStatusRepository.setStatusProcessing(updateId) и updateStatusRepository.setStatusProcessed(updateId) все еще должны быть вызваны для этого updateId.

  • Если имеются обновления продукта, они должны быть обработаны в ProductProcessingService.

На данный момент groupingBy и mapping дают мне набор с записью null вместо пустого набора, поэтому позже я удаляю все null идентификаторы продуктов.

List<ProductUpdate> productUpdateList = updateStatusRepository.getProductUpdates();
Map<String, Set<String>> productUpdateMap = productUpdateList
          .stream()
          .collect(
              Collectors.groupingBy(
                  ProductUpdate::getUpdateId,
                  Collectors.mapping(ProductUpdate::getProductNo, Collectors.toSet())));

productUpdateMap.forEach(
          (updateId, productIds) -> {
        try {
          updateStatusRepository.setStatusProcessing(updateId);
          productIds.remove(null);
          if(!productIds.isEmpty()) {
            productProcessingService.performProcessing(Lists.newArrayList(productIds));
          }
          updateStatusRepository.setStatusProcessed(updateId);
        } catch (Exception e) {
              //
        }
});

Я бы предпочел, если бы можно было использовать mapping таким образом, чтобы он доставлял пустой набор напрямую, если все значения null.

Есть ли способ сделать это элегантно?

1 Ответ

0 голосов
/ 10 января 2019

Вы можете использовать Collectors.filtering:

Map<String, Set<String>> productUpdateMap = productUpdateList
      .stream()
      .collect(Collectors.groupingBy(
               ProductUpdate::getVersionId,
               Collectors.mapping(ProductUpdate::getProductNo, 
                                  Collectors.filtering(Objects::nonNull, 
                                                       Collectors.toSet()))));

Я думаю, Collectors.filtering соответствует вашему конкретному случаю использования: он отфильтрует null номеров продуктов, оставляя пустой набор, если все номера продуктов окажутся null.


РЕДАКТИРОВАТЬ: Обратите внимание, что в этом случае использование Collectors.filtering в качестве выходного коллектора не то же самое, что Stream.filter перед сбором. В последнем случае, если мы отфильтровали элементы с номером продукта null перед сбором, мы могли бы получить карту без записей для какого-либо идентификатора версии, т. Е. Если все номера продуктов равны null для одного конкретного идентификатора версии.

Из Collectors.filtering документов:

API Примечание:

Коллекторы filtering() наиболее полезны при многоуровневом понижении, например, на groupingBy или partitioningBy. Например, с учетом потока Employee, чтобы накапливать сотрудников в каждом отделе, у которых зарплата выше определенного порога:

Map<Department, Set<Employee>> wellPaidEmployeesByDepartment
  = employees.stream().collect(
    groupingBy(Employee::getDepartment,
               filtering(e -> e.getSalary() > 2000,
                         toSet())));

Фильтрующий коллектор отличается от операции filter() потока. В этом примере предположим, что в каком-либо отделе нет сотрудников, чья зарплата выше порога. Использование фильтрующего коллектора, как показано выше, приведет к отображению из этого отдела в пустой Set. Если вместо этого будет выполнена операция потока filter(), то для этого отдела вообще не будет отображений.


РЕДАКТИРОВАТЬ 2: Я думаю, что стоит упомянуть альтернативу, предложенную @Holger в комментариях:

Map<String, Set<String>> productUpdateMap = productUpdateList
      .stream()
      .collect(Collectors.groupingBy(
               ProductUpdate::getVersionId, 
               Collectors.flatMapping(pu -> Stream.ofNullable(pu.getProductNo()), 
                                      Collectors.toSet())));
...