Java Reference
In-Depth Information
4. We use
collect(toList())
to put together a list of these nationalities.
When we put everything together, it ends up like this:
Set
<
String
>
origins
=
album
.
getMusicians
()
.
filter
(
artist
->
artist
.
getName
().
startsWith
(
"The"
))
.
map
(
artist
->
artist
.
getNationality
())
.
collect
(
toSet
());
This example shows the idiom of chaining operations a bit more clearly. The calls to
musi-
cians
,
filter
, and
map
all return
Stream
objects, so they are lazy, while the
collect
meth-
od is eager. The
map
method is another function that takes just a lambda and whose purpose
is to apply the function to every element in the
Stream
, returning a new
Stream
.
Our domain class here is actually quite convenient for us, in that it returns a
Stream
when we
want to get a list of the musicians on our album. In your existing domain classes, you prob-
ably don't have a method that returns streams—you return existing collection classes such as
List
or
Set
. This is OK; all you need to do is call the
stream
method on your
List
or
Set
.
Now is probably a good time to think about whether you really want to expose
List
and
Set
objects in your domain model, though. Perhaps a
Stream
factory would be a better choice.
The big win of only exposing collections via
Stream
is that it better encapsulates your do-
main model's data structure. It's impossible for any use of your domain classes to affect the
inner workings of your
List
or
Set
simply by exposing a
Stream
.
It also encourages users of your domain class to write code in a more modern Java 8 style.
It's possible to incrementally refactor to this style by keeping your existing getters and
adding new
Stream
-returning getters. Over time, you can rewrite your legacy code until
you've finally deleted all getters that return a
List
or
Set
. This kind of refactoring feels
really good once you've cleared out all the legacy code!
Refactoring Legacy Code
Having talked a bit about refactoring already, let's look at an example of some legacy collec-
tions code that uses loops to perform a task and iteratively refactor it into a stream-based im-
plementation. At each step of the refactor, the code continues to pass its tests, though you'll
either have to trust me on that one or test it yourself!