Reputation: 2025
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
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.
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.
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
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
Reputation: 5105
The solution would be:
bookingList.stream().collect(Collectors.groupingBy(Booking::getOfficeType, Collectors.counting()));
For reference: Collectors.counting()
Upvotes: 1