Java Reference
In-Depth Information
created by the
groupingBy
collector. We need a way of telling the
groupingBy
collector to
map
its list values as it's building up the result.
Each collector is a recipe for building a final value. What we really want is a recipe to give to
our recipe—
another
collector. Thankfully, the boffins at Oracle have thought of this use case
and provided a collector called
mapping
.
The
mapping
collector allows you to perform a
map
-like operation over your collector's con-
tainer. You also need to tell your
mapping
collector what collection it needs to store the res-
ults in, which you can do with the
toList
collector. It's turtles, I mean collectors, all the way
down!
Just like
map
, this takes an implementation of
Function
. If we refactor our code to use a
second collector, we end up with
Example 5-16
.
Example 5-16. Using collectors to find the names of every album that an artist has produced
public
public
Map
<
Artist
,
List
<
String
>>
nameOfAlbums
(
Stream
<
Album
>
albums
) {
return
return
albums
.
collect
(
groupingBy
(
Album:
:
getMainMusician
,
mapping
(
Album:
:
getName
,
toList
())));
}
In both of these cases, we've used a second collector in order to collect a subpart of the final
result. These collectors are called
downstream
collectors. In the same way that a collector is
a recipe for building a final value, a downstream collector is a recipe for building a part of
that value, which is then used by the main collector. The way you can compose collectors
like this makes them an even more powerful component in the streams library.
The primitive specialized functions, such as
averagingInt
or
summarizingLong
, are actu-
ally duplicate functionality over calling the method on the specialized stream themselves.
The real motivation for them to exist is to be used as downstream collectors.
Refactoring and Custom Collectors
Although the built-in Java collectors are good building blocks for common operations around
streams, the collector framework is very generic. There is nothing special or magic about the
ones that ship with the JDK, and you can build your own collectors very simply. That's what
we'll look at now.
You may recall when we looked at strings that we could write our example in Java 7, albeit
inelegantly. Let's take this example and slowly refactor it into a proper
String
-joining col-
lector. There's no need for you to use this code—the JDK provides a perfectly good
joining