Java 通过“set”的分组和映射进行收集,但如果所有值都是“null”,则需要一个空集
Java collect with grouping and mapping for `set`, but need an empty set if all values are `null`
在我的 Java 11 应用程序中,我想从存储库获取产品更新。一个产品更新有 updateId
和 productIds
列表要更新。
如果updateId = X
更新没有应该更新的产品编号,我还是想写信给另一个table我已经处理了更新X
; updateStatusRepository.setStatusProcessing(updateId)
和 updateStatusRepository.setStatusProcessed(updateId)
仍应为此 updateId
调用。
如果存在产品更新,它们应该在 ProductProcessingService
中处理。
现在,groupingBy
和 mapping
给我一个带有 null
条目的集合而不是一个空集合,这就是我后来删除所有 null
的原因产品 ID。
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) {
//
}
});
如果所有值都是 null
.
,我更愿意以这样一种方式使用 mapping
,它直接提供一个空集
有没有办法优雅地做到这一点?
你可以使用 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
.[=31,则留下一个空集=]
编辑: 请注意,在这种情况下,使用 Collectors.filtering
作为下游收集器与收集前使用 Stream.filter
不同。在后一种情况下,如果我们在收集之前过滤掉具有 null
产品编号的元素,我们最终可能会得到一个没有某些版本 ID 条目的映射,即如果所有产品编号都是 null
具体版本号。
来自 Collectors.filtering
文档:
API Note:
The filtering()
collectors are most useful when used in a multi-level reduction, such as downstream of a groupingBy
or partitioningBy
. For example, given a stream of Employee
, to accumulate the employees in each department that have a salary above a certain threshold:
Map<Department, Set<Employee>> wellPaidEmployeesByDepartment
= employees.stream().collect(
groupingBy(Employee::getDepartment,
filtering(e -> e.getSalary() > 2000,
toSet())));
A filtering collector differs from a stream's filter()
operation. In this example, suppose there are no employees whose salary is above the threshold in some department. Using a filtering collector as shown above would result in a mapping from that department to an empty Set
. If a stream filter()
operation were done instead, there would be no mapping for that department at all.
编辑 2: 我认为值得一提的是 @Holger 在评论中提出的替代方案:
Map<String, Set<String>> productUpdateMap = productUpdateList
.stream()
.collect(Collectors.groupingBy(
ProductUpdate::getVersionId,
Collectors.flatMapping(pu -> Stream.ofNullable(pu.getProductNo()),
Collectors.toSet())));
在我的 Java 11 应用程序中,我想从存储库获取产品更新。一个产品更新有 updateId
和 productIds
列表要更新。
如果
updateId = X
更新没有应该更新的产品编号,我还是想写信给另一个table我已经处理了更新X
;updateStatusRepository.setStatusProcessing(updateId)
和updateStatusRepository.setStatusProcessed(updateId)
仍应为此updateId
调用。如果存在产品更新,它们应该在
ProductProcessingService
中处理。
现在,groupingBy
和 mapping
给我一个带有 null
条目的集合而不是一个空集合,这就是我后来删除所有 null
的原因产品 ID。
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) {
//
}
});
如果所有值都是 null
.
mapping
,它直接提供一个空集
有没有办法优雅地做到这一点?
你可以使用 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
.[=31,则留下一个空集=]
编辑: 请注意,在这种情况下,使用 Collectors.filtering
作为下游收集器与收集前使用 Stream.filter
不同。在后一种情况下,如果我们在收集之前过滤掉具有 null
产品编号的元素,我们最终可能会得到一个没有某些版本 ID 条目的映射,即如果所有产品编号都是 null
具体版本号。
来自 Collectors.filtering
文档:
API Note:
The
filtering()
collectors are most useful when used in a multi-level reduction, such as downstream of agroupingBy
orpartitioningBy
. For example, given a stream ofEmployee
, to accumulate the employees in each department that have a salary above a certain threshold:Map<Department, Set<Employee>> wellPaidEmployeesByDepartment = employees.stream().collect( groupingBy(Employee::getDepartment, filtering(e -> e.getSalary() > 2000, toSet())));
A filtering collector differs from a stream's
filter()
operation. In this example, suppose there are no employees whose salary is above the threshold in some department. Using a filtering collector as shown above would result in a mapping from that department to an emptySet
. If a streamfilter()
operation were done instead, there would be no mapping for that department at all.
编辑 2: 我认为值得一提的是 @Holger 在评论中提出的替代方案:
Map<String, Set<String>> productUpdateMap = productUpdateList
.stream()
.collect(Collectors.groupingBy(
ProductUpdate::getVersionId,
Collectors.flatMapping(pu -> Stream.ofNullable(pu.getProductNo()),
Collectors.toSet())));