One important aspect of the Stream API that we have glossed
over until now is how to handle primitive types. Java generics do not allow a
primitive type to be used as a type parameter, so we cannot write Stream<int>.
However, the eagle-eyed reader might have noticed that in the last article, we
had a bit of code for finding the average age of some otters. This code
actually uses primitive types over most of the pipeline, so let’s unpack this a
bit and see how the primitive types are used in code like this.
First off, don’t be confused by the cast to double, which is
just to ensure that Java does a proper average instead of performing integer
division. The argument to map() is a lambda expression that takes in an Otter
and returns an int. If we could write the code using Java generics, the lambda
expression would be converted to an object that implements Function<Otter,
int>. However, because Java generics do not allow this, we need to encode the
fact that the return type is int in a different way—by putting it in the name
of the type. So the type that is actually inferred is
ToIntFunction<Otter>. This type is known as a primitive specialization of
the function type, and it is used to avoid boxing and unboxing between int and
Integer. This saves unnecessary generation of objects and allows us to use
function types that are specific to the primitive type that’s being used.
Let’s
break down the average calculation a little more. To get the age of each otter,
we use this expression:
Let’s look at the definition of the map() method that is
being called:
From this we can see that we are using the special function type ToIntFunction,
and we’re also using a specialized form of Stream to represent the stream of
ints. ots.stream().map(o -> o.getAge())
IntStream map(ToIntFunction<? super T> f);
No comments:
Post a Comment