Search code examples
javajava-streamcollectors

How to neglect objects during stream grouping or partitioning?


It is possible to neglect some elements during Collectors.groupingBy or Collectors.partitioningBy?

Of course I know I can place a .filter() anywhere in a stream. But my problem is that I have to run a rather complex and expensive evaluation, to decide in which "group" my objects should be divided into.

Moreover, there are always many objects that I would want to neglect during collecting.

Example: imagine a List<Foo>, that I want to split into 2 lists. That's easy, but how can I additionally neglect all objects that don't fit into my evaluated condition?

var map = foos.stream().collect(Collectors.groupingBy(
    foo -> {
        int bar = complexEvaluation(foo);
        if (bar > 1000) return true;
        if (bar < 0) return false;
        //TODO how to neglect the rest between 0-1000
    },
    Collectors.mapping(foo -> foo.id, Collectors.toSet())
));

Solution

  • Just use an enum to define your 3 cases:

    enum Categories {
        HIGH, LOW, NEGATIVE
    }
    
    var map = foos.stream().collect(Collectors.groupingBy(
        foo -> {
            int bar = complexEvaluation(foo);
            if (bar > 1000) return HIGH;
            if (bar < 0) return NEGATIVE;
            return LOW;
        },
        Collectors.mapping(foo -> foo.id, Collectors.toSet())
    ));
    

    Then ignore or remove LOW if you don’t need it. It also has the added benefits of giving more meaning to your categories instead of just naming them true/false, and making it easier to refactor if you need more categories in the future.

    Only drawback is that it builds a useless LOW set, but that’s only an issue if it is really big compared to the other sets and the complexEvaluation() operation.