VOOZH about

URL: https://www.javacodegeeks.com/2015/03/chaining-futures-in-scala.html

⇱ Chaining futures in scala - Java Code Geeks


Suppose I want to make coffee. This involves 4 steps:

  • 1a. grind coffee beans
  • 1b. heat water
  • 2. combine
  • 3. filter

All these steps take time, so they return a Future. This is our domain:
 
 

import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global //We need an executionContext to run futures
import scala.concurrent.duration._ //This provides the "1 second" syntax

class CoffeeBeans()
class GroundCoffee()
class ColdWater()
class WarmWater()
class UnfilteredCoffee()
class FilteredCoffee()

//we start out with beans and cold water
val beans = new CoffeeBeans()
val water = new ColdWater()

def grindBeans(beans: CoffeeBeans) = Future { new GroundCoffee() }
def heatWater(water: ColdWater) = Future { new WarmWater() }
def combine(groundCoffee: GroundCoffee, water: WarmWater) = Future { new UnfilteredCoffee() }
def filter(unfilteredCoffee: UnfilteredCoffee) = Future { new FilteredCoffee() }

One way we could chain the futures together is with onSuccess:

val fGrind: Future[GroundCoffee] = grindBeans(beans)
val fHeat: Future[WarmWater] = heatWater(water)
val fStep1: Future[(GroundCoffee, WarmWater)] = fGrind.zip(fHeat)

fStep1.onSuccess { case (groundCoffee, warmWater) =>
 val fCombine: Future[UnfilteredCoffee] = combine(groundCoffee, warmWater)
 fCombine.onSuccess { case unfilteredCoffee =>
 val fFilter: Future[FilteredCoffee] = filter(unfilteredCoffee)
 fFilter.onSuccess { case successCoffee =>
 println(s"$successCoffee is ready!")
 }
 }
}
Thread.sleep(1000)//wait for the coffee to be ready

Using flatmap we can simplify this to:

val fGrind: Future[GroundCoffee] = grindBeans(beans)
val fHeat: Future[WarmWater] = heatWater(water)
val fStep1: Future[(GroundCoffee, WarmWater)] = fGrind.zip(fHeat)

val fCombine: Future[UnfilteredCoffee] = fStep1.flatMap {
 case (groundCoffee, warmWater) => combine(groundCoffee, warmWater)
}
val fFilter: Future[FilteredCoffee] = fCombine.flatMap {
 case unfilteredCoffee => filter(unfilteredCoffee)
}
val flatmapCoffee: FilteredCoffee = Await.result(fFilter, 1 second)

Notice that we have the future of our filtered coffee at the highest level. This is nice! We can return it, or call Await.Result on it to wait for our coffee to be ready.

Since a for comprehension is a shorter way of writing flatMaps, we can simplify it to this:

val fFor = for {
 groundCoffee <- grindBeans(beans)
 warmWater <- heatWater(water)
 unfilteredCoffee <- combine(groundCoffee, warmWater)
} yield filter(unfilteredCoffee)
val forCoffee: FilteredCoffee = Await.result(fFilter, 1 second)

cheers!

Reference: Chaining futures in scala from our JCG partner Tammo Sminia at the JDriven blog.
Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Thank you!

We will contact you soon.

👁 Photo of Arthur Arts
Arthur Arts
March 18th, 2015Last Updated: March 17th, 2015
0 105 1 minute read

Arthur Arts

Arthur Arts is an experienced Enterprise Java software engineer and hands-on Agile Coach and Scrum Master. He has a strong focus on agile engineering principles and practices and loves to share his knowledge and learn from others. He has his own company Coded Value, is a passionate photographer and writes for agilearts.nl.
Subscribe

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button
Close
wpDiscuz