abidinberkay
abidinberkay

Reputation: 2025

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

I have a list of Booking and this Booking has field OfficeType as enum as follow

@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;

I get the list of Booking from db, and I need to return to client that list and grouped by Office type and count as:

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

How can I stream that list into that map grouping by OfficeType and counts ?

Upvotes: 0

Views: 1134

Answers (3)

Alexander Ivanchenko
Alexander Ivanchenko

Reputation: 28978

To generate a Map of type Map<OfficeType,Integer> you can either use three-args version of Collector toMap(), or a combination of Collectors collectiongAndThen() and groupingBy() + collector counting() as a downstream of grouping.

toMap()

If you're not expecting a large amount of elements having the same id, you can use the following single-collector solution based on three-args toMap():

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

Note regarding performance:

There can be a small overhead caused generating new instances of Integer (because code above operates with wrapper type and primitive int). But all instances of Integer having a value of less than 128 are cached by the JVM (i.e. they would be created only once, and then the same reference would be used). So if there's roughly a hundred of elements having identical id there would be no tangible difference between this single collector-solution and the one listed below.

collectiongAndThen() & groupingBy()

This approach groupingBy() in conjunction with counting() as a downstream might be more performant when number if the data is massive. In this case, accumulation through collector counting(), which calculates resulting value using primitive long, can more advantages.

To transform the Long into Integer we can wrap groupingBy() with collectingAndThen().

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

Upvotes: 3

Find Bugs
Find Bugs

Reputation: 145

Use lambda expression like below:

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

Upvotes: 2

Toni
Toni

Reputation: 5105

The solution would be:

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

For reference: Collectors.counting()

Upvotes: 1

Related Questions