44 Working With Future: Map and Flatmap - Get Programming With Scala
44 Working With Future: Map and Flatmap - Get Programming With Scala
flatMap
Consider this
The type Future has an implementation for the map , flatten , and
flatMap methods. You’ll see them in action in the following subsections.
You will notice that they have many similarities with those you are al-
ready encountered, such as Option , List , and Try .
Let’s consider again your program to place orders in a store. Suppose that
after checking for a product’s availability, you’d like to either place an or-
der or reject the request.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext
case class Availability(id: Int, quantity: Double)
case class Order(id: Int,
customerId: Int,
productId: Int,
quantity: Double)
Future catches any exception; you can throw them knowing that Future
will contain them.
scala> Future(12/2).map(_ * 3)
val res0: scala.concurrent.Future[Int] = Future(Success(18))
scala> Future(12/0).map(_ * 3)
val res1: scala.concurrent.Future[Int] = Future(Failure(java.lang.ArithmeticException: / b
Consider the function you wrote in listing 44.1 to check the availability
for a product and create an order. Its function createOrder returns a
value of type Order . Imagine the function createOrder now needs to
write to a database asynchronously and that you need to change its re-
turn type from Order to Future[Order] . This causes its function
placeOrder to return a value of type Future[Future[Order]] .
scala> twelveOverZero
val twelveOverZero: scala.concurrent.Future[Int] = Future(Failure(java.lang.ArithmeticExce
scala> Future(Future(12/2)).flatten
val res0: scala.concurrent.Future[Int] = Future(Success(6))
scala> Future(5).flatten
error: Cannot prove that Int <:< scala.concurrent.Future[S].
// You can only invoke the method flatten on nested structures
Consider the snippet of code you wrote in listing 44.3. There is a more ele-
gant way of achieving the same result.
The method flatMap is the combination of the map and flatten oper-
ations. For an instance of Future[T], the function flatMap takes one
parameter f of type T => Future[S] and an implicit execution con-
text to produce an instance of type Future[S] . It has the following
signature:
scala> twelveOverTwo
val twelveOverTwo: scala.concurrent.Future[String] = Future(Success(6))
// twelveOverTwo has now completed successfully
Table 44.1 summarizes the signature and usage of the methods map ,
flatten , and flatMap acting on Future .
Summary
You saw how to use the function map to transform the value your
asynchronous computation produces.
You learned how to merge two nested instances of Future into one
using the flatten operation.
You discovered how the flatMap method allows you to express an
execution dependency between two asynchronous computations.
Let’s see if you got this!
TRY THIS Consider the following snippet of code that defines a func-
tion to list the content in a given directory:
import java.io.File
import scala.concurrent.{ExecutionContext, Future}