Java Reference
In-Depth Information
In each case, we've got the boilerplate code of adding some code for each album to the
total—for example, the length of each track or the number of musicians. We're failing at re-
using common concepts and also leaving ourselves more code to test and maintain. We can
shorten and tighten this code by rewriting it using the
Stream
abstraction and the Java 8 col-
lections library.
Example 7-6
is what we would come up with if we directly translated the im-
perative code to streams.
Example 7-6. A refactor of our imperative Order class to use streams
public
public
long
long
countRunningTime
() {
return
return
albums
.
stream
()
.
mapToLong
(
album
->
album
.
getTracks
()
.
mapToLong
(
track
->
track
.
getLength
())
.
sum
())
.
sum
();
}
public
public
long
long
countMusicians
() {
return
return
albums
.
stream
()
.
mapToLong
(
album
->
album
.
getMusicians
().
count
())
.
sum
();
}
public
public
long
long
countTracks
() {
return
return
albums
.
stream
()
.
mapToLong
(
album
->
album
.
getTracks
().
count
())
.
sum
();
}
It still suffers from the same reuse and readability issues, because there are certain abstrac-
tions and commonalities that are only expressible in domain terms. The streams library won't
provide a method for you to count the number of a certain thing per album—that's the kind
of domain method that you should be writing yourself. It's also the kind of domain method
that was very hard to write before Java 8 because it's doing a different thing for each method.
Let's think about how we're going to implement such a function. We're going to return a
long
with the count of some feature for all the albums. We also need to take in some kind of
lambda expression that tells us what the number for each album is. This means we need a
method parameter that returns us a
long
for each album; conveniently, there is already a
ToLongFunction
in the Java 8 core libraries. As shown in
Figure 7-1
, it is parameterized by
its argument type, so we're using
ToLongFunction<Album>
.