Home » Java » Java8, Is there a filtering collector?

Java8, Is there a filtering collector?

Posted by: admin December 28, 2021 Leave a comment

Questions:

I want to group a collection but I don’t want the aggregations to include some values. What’s the best solution to do that?

A solution could be a collector filtering(Predicate,Collector) but there is no such collector. Is there any way to do it without implementing your own collector?

IntStream.range(0,100).collect(
    groupingBy(
       i -> i % 3,
       HashMap::new,
       filtering( i -> i % 2 == 0, toSet() )
    )
);
Answers:

The only other way I’m aware of is to do the filtering beforehand, that is,

 stream.filter(filterPredicate).collect(collector)

That said, it’s not clear what you’re actually trying to do with your filtering function, which takes three arguments instead of two.

I suspect you are trying to map a function over elements that match a filter, but that’s itself a map, which you can do easily enough:

 Collectors.mapping(input -> condition(input) ? function(input) : input, collector)

And making your own collector isn’t actually that difficult:

static <T, A, R> Collector<T, A, R> filtering(
    Predicate<? super T> filter, Collector<T, A, R> collector) {
  return Collector.of(
      collector.supplier(),
      (accumulator, input) -> {
         if (filter.test(input)) {
            collector.accumulator().accept(accumulator, input);
         }
      },
      collector.combiner(),
      collector.finisher());
}

###

In Java 9 there’s a new filtering collector :

Map<Department, Set<Employee>> wellPaidEmployeesByDepartment = employees.stream()
  .collect(groupingBy(Employee::getDepartment,
      filtering(e -> e.getSalary() > 2000, toSet())));