如何在Java中将groupBy及其计数列表放入Map对象中?

How to groupBy and its count list of items into Map object in Java?

提问人:abidinberkay 提问时间:10/25/2022 更新时间:10/26/2022 访问量:604

问:

我有一个 Booking 列表,此 Booking 的字段 OfficeType 为枚举,如下所示

@Data
@Entity
@TypeDef(name = "json", typeClass = JsonStringType.class)
public class Booking {
@Id
    @GeneratedValue(generator = "uuid2")
    @GenericGenerator(name = "uuid2", strategy = "uuid2")
    @Column(name = "id", nullable = false, columnDefinition = "VARCHAR(36)")
    private String id;

   

    @Column(name = "office_type")
    private OfficeType officeType;

我从数据库获取 Booking 列表,我需要返回到客户端,该列表并按 Office 类型分组,计数为:

List<Booking> bookingList = bookingRepository.findByStatus(Status.APPROVED);
        Map<OfficeType, Integer> officeTypeMap = new HashMap<>();

如何按 OfficeType 和计数将该列表流式传输到该地图分组中?

java spring spring-boot java-stream 轻量级流 api

评论


答:

1赞 Toni 10/25/2022 #1

解决方案是:

bookingList.stream().collect(Collectors.groupingBy(Booking::getOfficeType, Collectors.counting()));

供参考:Collectors.counting()

2赞 Find Bugs 10/25/2022 #2

使用如下所示的 lambda 表达式:

List<Booking> bookingList = bookingRepository.findByStatus(Status.APPROVED);
Map<OfficeType, Integer> officeTypeMap = bookingList.stream().collect(Collectors.groupingBy(Booking::getOfficeType,Collectors.counting()));

评论

0赞 Toni 10/25/2022
这是错误的,您是按 id 而不是 OfficeType 分组的。
0赞 Find Bugs 10/25/2022
对不起,这是一个演示。我刚才编辑了。
3赞 Alexander Ivanchenko 10/25/2022 #3

要生成 of 类型,您可以使用 Collector 的 three-args 版本,也可以使用 Collectors 和 + collector 的组合作为分组的下游。MapMap<OfficeType,Integer>toMap()collectiongAndThen()groupingBy()counting()

toMap()

如果你不希望有大量的元素具有相同的元素,你可以使用以下基于三参数的单收集器解决方案 toMap():id

List<Booking> bookingList = bookingRepository.findByStatus(Status.APPROVED);
        
Map<OfficeType, Integer> officeTypeMap = bookingList.stream()
    .collect(Collectors.toMap(
        OfficeType::getId,
        i -> 1,
        Integer::sum
    ));

关于性能的注意事项:

可能会有很小的开销,导致生成新的实例(因为上面的代码使用包装器类型和原语进行操作)。但是,所有值小于 的实例都会被 JVM 缓存(即它们只会创建一次,然后使用相同的引用)。因此,如果大约有一百个相同的元素,那么这个单一的收集器解决方案与下面列出的解决方案之间就没有明显的区别。IntegerintInteger128id

collectiongAndThen() & groupingBy()

如果数据量很大,则将 groupingBy() 与 counting() 结合使用作为下游的方法在 number 时可能性能更高。在这种情况下,通过收集器进行累积,它使用原始计算结果值,可以更有优势。counting()long

要将 转换为 ,我们可以用 collectingAndThen() 进行包装。LongIntegergroupingBy()

List<Booking> bookingList = bookingRepository.findByStatus(Status.APPROVED);
        
Map<OfficeType, Integer> officeTypeMap = bookingList.stream()
    .collect(Collectors.collectingAndThen(
        Collectors.groupingBy(OfficeType::getId, Collectors.counting()),
        Long::intValue)
    ));