Vavr’s flatMap in action
TL;DR Whenever your cargo is inside a ship carried by another ship — flatMap that ship!
Programming is often about transforming data from one type to another. Vavr provides the map
method which is invoked during a so-called happy path: you map a Try
’s success, an Option
’s value, an Either
’s right, a Future
’s successful result and finally a List
’s element.
Every time you type map
, your IDE provides you with a list of suggestions and typically a flatMap
method is present among them. If you’re curious, when and how to use this mysterious thing, here are some examples.
1) flatMap that List of Lists
In this example flatMap
is used to first map
each element of the listOfLists
List
, called innerList
, to another List
. Every innerList
element, a List
of String
s is left untouched — that’s what x -> x
stands for. Another way of returning a function’s input in a map
operation is to use java.util.function.Function.identity()
.
The second task of flatMap
is to flatten the result. In case of a List
of List
s, this means to return a single List
with elements from all the inner List
s: [[a, b], [c, d], [e, f, g]]
becomes [a, b, c, d, e, f, g]
.
A slightly more complex version of this example is to apply a map function to each of the inner List
’s element, like toLowerCase()
.
To sum it up: flatMap
on a List
of List
s applies a map
function on each element of the outer List
and returns one List
.
2) flatMap that List of Options
Similarly flatMap
is able to flatten a List
of Option
s of String
to return a List
of String
s. The neat thing here is that only a success is processed (mapped) — in case of an Option
a success is when it is defined.
Obviously we can also apply a map
function on every element wrapped by an Option. Here it is the toLowerCase()
method:
To sum it up: flatMap
on a List
of Option
s applies a map
function on each defined Option
and returns one List
of every wrapped element.
3) flatMap that List of Tries
Last basic example and we’re ready to move to the more fancy stuff. A List
of Try
objects, each wrapping a failure or a success (String
value), is first mapped. To keep it short, Function.identity()
leaves the successes and filters out any failures leaving us with a List
of successful Try
objects. Finally this list is flattened, which means to extract the success values from the Try
objects and return them as a List
.
To sum it up: flatMap
applied to a List
of Tries
runs a map
function on each Try.Success
and returns a List
of every wrapped element.
These are very basic examples doing trivial map operations. They just flatten the collection of collections returning one single collection. This can be applied to other functional data structures like Array
, Vector
, Queue
, Set
and Map
.
4) flatMap that Try of Tries
Once you get used to functional programming with Vavr and start using Try
in public methods you may soon end up with a far more common scenario, where from within a Try
context you call another method returning a Try
:
The method wrapThrowOnXYZ()
returns a Try
. In case of a success we map the wrapped value to another Try
by calling anotherTryWrapper()
. And this leaves us with a Try
of a Try
. There are three possible results:
- the outer Try
is a failure,
- the outer Try
is a success but the the inner Try
is a failure,
- the outer Try
is a success and the the inner Try
is a success.
To extract the result (Try
of a Try
) we cannot simply call get()
on the outer Try
. First we need to check if it is a success with isSuccess()
. Otherwise we could end up with an exception being thrown, if the Try
would wrap a failure and there would go our “don’t throw, return a Try” professional programming style.
This can be fixed with flatMap
:
flatMap
will either return a success wrapping a String
or one of the two possible failures: an exception from wrapThrowOnXYZ()
or an exception from anotherTryWrapper()
.
To sum it up: flatMap
on a Try
of Tries
returns a Try.Success
if all the Tries
are successful or the first Try.Failure
encountered in the chain.
5) flatMap that Option of Option
The next example shows a very similar approach, just with Option
s.
Once you’re methods return Option
s wrapping a value or an Option.None
, you’ll encounter this situation: from within an Option
context you provide a mapper returning also an Option
:
Again we’re left with 3 possible results:
- the outer Option
is a None
,
- the outer Option
is a Some
, but the inner Option
is a None
,
- the outer Option
is a Some
and the inner Option
is a Some
.
We cannot call get()
on the outer Option
to unpack the inner Option
, without calling isDefined()
first. Otherwise an exception is thrown if the Option
is a None
. What we want is just one Option
being either None
or Some
. And here flatMap
shines again.
To sum it up: flatMap
applied on an Option
of another Option
results in an Option.Some
if all Option
s are Some
or an Option.None
otherwise.
6) flatMap that Either of Either
As stated earlier, map applies a mapping function on a success. In case of an Either
, this is the Right
value. Having said that, let’s see how to apply flatMap
on an Either
.
The outerEither
Either
is
- an Either.Right
wrapping the age
String
, if age
is not null,
- an Either.Left
wrapping “empty” if age
is null.
Applying flatMap
returns
- an Either.Left
wrapping “empty” if outerEither
is Either.Left
,
- an Either.Left
wrapping a String
that could not be parsed to an Integer
,
- an Either.Right
wrapping an Integer
if age
could be parsed successfully.
To sum it up: flatMap
on an Either
of another Either
results in an Either.Right
if all Either
s are Right
or an Either.Left
wrapping the first Left
encountered.
All the examples are available on GitHub and there is also a test suite provided to play around with different inputs.
To finally sum it up: there are many ways flatMap
can be used to process data. However now it should be clear what it means to map a List
element, a Try.Success
, an Option.Some
,a completed Future
or an Either.Right
and then flatten the result.
Looking for Scala and Java Experts?
We will make technology work for your business. See the projects we have successfully delivered.