Home > Back-end >  Stream Pattern Matching Filter InstanceOf
Stream Pattern Matching Filter InstanceOf

Time:11-13

Suppose we have a Stream of Animals. We have different Subclasses of Animals, and we want to apply a filter on the stream to only have the Zebras of the Stream. We now still have a Stream of Animals, but only containing Zebras. To get a stream of Zebras we still need to cast.

Stream<Zebra> zebraStream = animalStream
    .filter(Zebra.class::isInstance)
    .map(Zebra.class::cast);

Java 14 introduced pattern matching for instanceOf so we can now use:

if (animal instanceOf Zebra zebra) {
    System.out.println(zebra.countStripes());
}

Is there a way to use pattern matching in stream pipes? Of course you could do something like this:

Stream<Zebra> zebraStream = animalStream.map(animal -> {
        if (animal instanceof Zebra zebra) {
            return zebra;
        }
        return null;
    })
    .filter(Objects::nonNull);

But IMHO this is really ugly.

CodePudding user response:

To coerce a Stream of supertype to a Stream of one of its subtypes, you can do the following using Class.isAssignableFrom() and Class.cast():

Stream<Animal> animalStream = Stream.of();

Stream<Zebra> zebraStream = animalStream
    .filter(animal -> Zebra.class.isAssignableFrom(animal.getClass()))
    .map(Zebra.class::cast);

Or alternatively, you can make use of the Pattern matching for instanceof and Java 16 mapMulty():

Stream<Animal> animalStream = Stream.of();

Stream<Zebra> zebraStream = animalStream
    .mapMulti((animal, consumer) -> {
        if (animal instanceof Zebra zebra) consumer.accept(zebra);
    });

CodePudding user response:

I think you are almost done it! Just use filter instead of map:

Stream<Zebra> zebraStream = animalStream.stream()
                                        .filter(animal -> animal instanceof Zebra)
                                        .map(Zebra.class::cast);
  • Related