Java Reference
In-Depth Information
and we want them merged together. So, if we replace that
forEach
block with a
flatMap
call, we end up at
Example 3-22
.
Example 3-22. Refactor step 3: finding names of tracks over a minute in length
public
public
Set
<
String
>
findLongTracks
(
List
<
Album
>
albums
) {
Set
<
String
>
trackNames
=
new
new
HashSet
<>();
albums
.
stream
()
.
flatMap
(
album
->
album
.
getTracks
())
.
filter
(
track
->
track
.
getLength
() >
60
)
.
map
(
track
->
track
.
getName
())
.
forEach
(
name
->
trackNames
.
add
(
name
));
return
return
trackNames
;
}
That looks a lot better, doesn't it? Instead of two nested
for
loops, we've got a single clean
sequence of method calls performing the entire operation. It's not quite there yet, though.
We're still creating a
Set
by hand and adding every element in at the end. We really want the
entire computation to just be a chain of
Stream
calls.
I haven't yet shown you the recipe for this transformation, but you've met one of its friends.
Just as you can use
collect(toList())
to build up a
List
of values at the end, you can
also use
collect(toSet())
to build up a
Set
of values. So, we replace our final
forEach
call with this
collect
call, and we can now delete the
trackNames
variable, arriving at
Example 3-23. Refactor step 4: finding names of tracks over a minute in length
public
public
Set
<
String
>
findLongTracks
(
List
<
Album
>
albums
) {
return
return
albums
.
stream
()
.
flatMap
(
album
->
album
.
getTracks
())
.
filter
(
track
->
track
.
getLength
() >
60
)
.
map
(
track
->
track
.
getName
())
.
collect
(
toSet
());
}
In summary, we've taken a snippet of legacy code and refactored it to use idiomatic streams.
At first we just converted to introduce streams and didn't introduce any of the useful opera-
tions on streams. At each subsequent step, we moved to a more idiomatic coding style. One
thing that I haven't mentioned thus far but that was very helpful when actually writing the
code samples is that at each step of the way I continued to run unit tests in order to make sure
the code worked. Doing so is very helpful when refactoring legacy code.