简体   繁体   中英

Java 8 Streams - Handle Nulls inside Collectors.groupingBy

I have a list of objects in variable "data". I want to filter them (on ActivityType='Deal_Lost') and then group them using one of the field (DealLostReason) and store in a map with DealLostReason and respective count.

Below method works perfectly fine when there are no NULL values returned by c.getDealLostReason(). However, if there is a null value in any of the record, it just returns null instead of grouped values.

Map<Object, Long> collect = data.stream().
    filter(c -> c.getActivityType().equals(ActivityTypeEnum.Deal_Lost))
    .collect(Collectors.groupingBy(c -> { 
        return c.getDealLostReason(); }, Collectors.counting()))));

Can anyone help me on how to handle null values inside lambda expression. I want the null values to be calculated as "Other". ie if any record has null, it should be calculated as "OTHER". Below is the SQL query I am trying to achieve.

USE egcity;
SELECT 
    CASE WHEN dealLostReason IS NULL THEN 'Other' ELSE dealLostReason END,
    COUNT(*) from LeadActivity
WHERE 
        activity_date_time>='2021-04-01' AND activity_date_time<='2021-05-01'
AND activityType = 'Deal_Lost'
GROUP BY dealLostReason;

在此处输入图像描述

You can use ternary operator to map null having objects counts to OTHER

Map<Object, Long> collect = data.stream()
           .filter(c->c.getActivityType().equals(ActivityTypeEnum.Deal_Lost))
           .collect(Collectors.groupingBy(c -> c.getDealLostReason() == null ? "OTHER" : c.getDealLostReason(),Collectors.counting())));
                                      

null s should be avoided at the source. That said, handling null s mid-stream can be done using Optional s. Here's a dirty little gist to get you started.

    Map<Object, Long> collect = data.stream()
            .map( x -> Optional.of( x ).orElseGet( () -> Something.defaultSomething() ) )
            .filter( c -> c.getActivityType().equals(ActivityTypeEnum.Deal_Lost))
            .collect( Collectors.groupingBy( c ->
            {
                return c.getDealLostReason();
            }, Collectors.counting()));

with the defaultSomething some implementation of the type representing the absent value.

Even better would be to postpone the optional-unwrapping to the very last moment; in this case the query construction: ie Don't need to know, don't wanna know .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM