Search code examples
javajava-streamrefactoringjpqlcollectors

How to avoid getting null elements in list while collecting and grouping JPA Tuple to Map in Java?


I have following JPQL statement:

select e as entity, c.type as config_type 
from Entity e 
         left join Config c on e = c.entity 
where c.type = (select t from Type t where t.name = 'SHOP')

I want to collect this result to Map grouping by Entity. The value of map, should be List of config types. This list can be also empty if Entity doesn't have any config specified. I have already wrote some method which accomplishes the task:

public Map<Entity, List<ConfigType>> getGroupedEntityToConfigTypesMap() {
    return em.createNamedQuery(Entity.NQ_GET_ENTITY_TO_CONFIG_TYPE, Tuple.class)
        .getResultStream()
        .collect(Collectors.groupingBy(
            tuple -> ((Entity) tuple.get("entity")),
            Collectors.mapping(tuple -> ((ConfigType) tuple.get("config_type")),
                Collectors.collectingAndThen(Collectors.toList(), list ->
                    list.stream()
                        .filter(Objects::nonNull)
                        .collect(Collectors.toUnmodifiableList())))
        ));
}

From my point of view, it doesn't look so good because while collecting values, I have to iterate one more time through every List and check if this list doesn't contain only null value, thus it is not so efficient.

Is there any better way to collect Tuple to Map with groupingBy more efficient and elegant than now? The goal is to collect also those entries which doesn't have any Configs but it should be mapped to empty list instead of Lists.of(null);.


Solution

  • Maybe you want to check out Collections.filtering. I tried to incorporate it into your solution and came up with a little bit more concise and efficient solution. But I have not tested it yet, sorry. Also note, that I returned the filtered objects as a Set instead of a List. Feel free to keep going with the List if that fits your need best. And please hit me up if it worked or you have any other questions.

    Stream.of(tuple)
            .collect(groupingBy(
                record -> (tuple.get("entity")),
                mapping(record -> (tuple.get("config_type")),
                    Collectors.filtering(Objects::nonNull, Collectors.toSet()))
            ));