With Java 8 Streams, is it possible to encapsulate and reuse intermediate stream operations in some way that won't break the stream pipeline?
Consider this example from the Java Tutorial on streams:
double average = roster
.stream()
.filter(p -> p.getGender() == Person.Sex.MALE)
.mapToInt(Person::getAge)
.average()
.getAsDouble();
Suppose I need to use the filter and mapToInt operations in different places throughout my code. I might want try and to encapsulate that logic so it can be reused, for example:
IntStream maleAges(Stream<Person> stream) {
return stream
.filter(p -> p.getGender() == Person.Sex.MALE)
.mapToInt(Person::getAge)
}
This is nice, but to use it I might have to make a mess of the stream pipeline. For example, if I want the average age of men named Bob:
double averageBob =
maleAges(roster
.stream()
.filter(p -> "Bob".equals(p.getName()))
)
.average()
.getAsDouble();
Is there some better way to do it? I'm thinking of something along these lines:
double averageBob = roster
.stream()
.filter(p -> "Bob".equals(p.getName()))
.apply(this::maleAges) // Doesn't compile
.average()
.getAsDouble();
One way to do it would be to instead taking a Stream, to take a single Person and emit an IntStream such as :
final Predicate<Person> isMale = p -> p.getGender() == Person.Sex.MALE;
final Function<Person, IntStream> maleAges = person -> isMale.test(person)
? IntStream.of(person.age)
: IntStream.empty();
final double averageT = roster
.stream()
.flatMapToInt(maleAges)
.average()
.getAsDouble();
This way you can reuse your maleAges function anywhere !
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With