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);