Placeholder object for value that may not yet exist, revolve around ExecutionContext which has access to a thread pool similar to Executor design pattern, commonly you map over it
val futureHttpResult = WS.url(“http://catpictures.dev/top10”).get()
val webPage = futureHttpResult.map { catPicturesHttpBody =>
val parsed = parse(catPicturesHttpBody)
val firstPictureUrl = parsed.get(0)
Ok(myWebPageTemplate(firstPictureUrl))
}
webPage
Nonblocking Looks sequential, but when it does load inner map block runs
Promises like syntax
val fut1: Future[Assignment] = Future(nextAssignmentStore.get(classId1))
val fut2: Future[Assignment] = Future(nextAssignmentStore.get(classId2))
val fut3: Future[Assignment] = Future(nextAssignmentStore.get(classId3))
val allFutures: List[Future[Assignment]] = List(fut1, fut2, fut3)
// delegate the execution of fatMatrix.inverse() to an ExecutionContext and embody the result of the computation in inverseFuture.
val inverseFuture: Future[Matrix] = Future {
fatMatrix.inverse() // non-blocking long lasting computation
}(executionContext)
implicit val ec: ExecutionContext = ...
val inverseFuture : Future[Matrix] = Future {
fatMatrix.inverse()
} // ec is implicitly passed
Defining Global Execution Context
//1
import scala.concurrent.ExecutionContext.Implicits.global
//2
implicit val executor = scala.concurrent.ExecutionContext.global
//3
Future { /* do something */ }(executor)
States
not yet completed, not completed
completed with value or exception, completed
failed with exception or successfully completed with value
Immutable after it becomes completed
Callbacks
f onComplete {
case Success(posts) => for (post <- posts) println(post)
case Failure(t) => println("An error has occurred: " + t.getMessage)
}
Callback takes a Try[T] => U where Try[T] is like an option but contains either the variable or an exception
Combinators
Only Success (foreach)
f foreach { posts =>
for (post <- posts) println(post)
}
Change Future Value (map)
val rateQuote = Future {
connection.getCurrentValue(USD)
}
val purchase = rateQuote map { quote =>
if (isProfitable(quote)) connection.buy(amount, quote)
else throw new Exception("not profitable")
}
purchase foreach { _ =>
println("Purchased " + amount + " USD")
}
exception are propagated
For comprehensions(flatmap & withfilter)
flatmap -> like map but ft returns a future not a value, used to call ft's that return future on value yet to be computed
for loop basically allows several flatMaps then a final map yielding a Future value
futures start running immediately on seperate threads and main thread runs through this without blocking
resultF is just a Future that waits for component parts to finish before completing itself
val threeF = Future(3)
val fourF = Future(4)
val fiveF = Future(5)
val resultF = for{
three <- threeF
four <- fourF
five <- fiveF
}yield{
three * four * five
}
//EQUALS
val resultF = threeF.flatMap(three => fourF.flatMap(four => fiveF.map(five => three * four * five)))
Example 2
val usdQuote = Future { connection.getCurrentValue(USD) }
val chfQuote = Future { connection.getCurrentValue(CHF) }
val purchase = for {
usd <- usdQuote
chf <- chfQuote
if isProfitable(usd, chf)
} yield connection.buy(amount, chf)
purchase foreach { _ =>
println("Purchased " + amount + " CHF")
}
//EQUALS
val purchase = usdQuote flatMap {
usd =>
chfQuote
.withFilter(chf => isProfitable(usd, chf)) //throws exception in future if bool false
.map(chf => connection.buy(amount, chf))
}
Exception recovery
recover
RecoverWith
fallbackTo
Coursera Usage
future.flatMap(x =>
x
...
y.flatMap( t =>
t
)
)
is the same as
x <- future
Thread blocks while the future waits to finish and collapse