Home > Mobile >  Stream map on filter
Stream map on filter

Time:11-18

When you have a Stream of Objects you can filter on them pretty elegantly.

swimmingAnimalStream = animalStream
    .filter(Animal::canSwim);

When you have slightly more complex filters instead of using Method references you have to use Lambdas.

greenAnimals = animalStream
    .filter(animal -> animal.getColor().equals(Colors.GREEN));

Is there a way to map the value before filtering on it, but still have the complete object after the filter? So the fallowing is not what I want:

animalStream
    .map(Animal::getColor)
    .filter(Colors.GREEN::equals)

With this I would be left with color information only. What I also would like to avoid is extracting the method. I am looking for a more streamlined way of doing this. Something like this for example:

animalStream
    .filter(Colors.GREEN::equals, Animal::getColor);

The method signature of this filter method would look like this.

<MAPPED> Stream<T> filter(Predicate<MAPPED> filter, Function<? super T, MAPPED> mappingFunction);

Even better would be a version where you could join multiple mapping functions. On the fly one could maybe use a varargs for the mappingFunction. But I honestly don’t know how that would be possible with Generics. But that’s a different story.

The solution should also be able to use whatever Predicate that one could imagine. Equals is just an Example. Another example would be to check if a field from the object is present.

animalWithMotherStream = animalStream
    .filter(Optional::isPresent, Animal::getMother);

Does anyone now a cleaner Solution, or a library that does this already?

CodePudding user response:

StreamEx, a library that provides extended stream methods and classes, has filterBy:

public <K> StreamEx<T> filterBy​(Function<? super T,​? extends K> mapper, K value)

Returns a stream consisting of the elements of this stream for which the supplied mapper function returns the given value.

This method behaves like filter(t -> Objects.equals(value, mapper.apply(t))).

CodePudding user response:

filter accepts a Predicate, whose function can only return a boolean. There's no other method signature.

If you want to filter by all green animals, you'd use

animalStream
    .filter(a -> Colors.GREEN.equals(a.getColor()))

or

Predicate<Animal> isGreen = (a) -> Colors.GREEN.equals(a.getColor());
Stream<Animal> greenAnimals = animalStream.filter(isGreen);

Don't use map unless you want a Stream<COLOR>

join multiple mapping functions

You can chain them, rather than join - .stream().map().map(), but as you discovered, this does not preserve the original type.

  • Related