Exercises
Here are three exercises focusing on Scala Futures to practice asynchronous programming. These exercises cover different aspects of working with Futures, including basic usage, composition, error handling, and integration with external services or databases.
Exercise 1: Asynchronous Data Processing
Objective: Implement an asynchronous method that processes a list of integers. The processing should square each number and then return the sum of all squared numbers. Use Futures to perform the squaring operations in parallel.
Task:
- Create a method
squareNumberthat takes anIntand returns aFuture[Int]representing the square of the number. - Implement a method
sumOfSquaresthat accepts aList[Int]and returns aFuture[Int]with the sum of the squares of the list elements, computed asynchronously.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
def squareNumber(number: Int): Future[Int] = Future {
number * number
}
def sumOfSquares(numbers: List[Int]): Future[Int] = {
Future.sequence(numbers.map(squareNumber)).map(_.sum)
}
Exercise 2: Combining Futures with for-comprehension
Objective: Write a function that asynchronously fetches the current temperatures (mocked as random values) for two cities and then computes the average temperature. Each city's temperature should be fetched in parallel, and the averaging should be done once both temperatures are available.
Task:
- Implement two functions,
getTemperature(city: String): Future[Double], that simulate fetching temperature data for each city. - Write a function
averageTemperature(city1: String, city2: String): Future[Double]that uses for-comprehension to wait for both temperatures and then computes the average.
import scala.concurrent.Future
import scala.util.Random
import scala.concurrent.ExecutionContext.Implicits.global
def getTemperature(city: String): Future[Double] = Future {
Thread.sleep(Random.nextInt(500)) // Simulate network delay
20 + Random.nextInt(15) // Random temperature
}
def averageTemperature(city1: String, city2: String): Future[Double] = {
for {
temp1 <- getTemperature(city1)
temp2 <- getTemperature(city2)
} yield (temp1 + temp2) / 2
}
Exercise 3: Error Handling in Futures
Objective: Implement a function that tries to parse a list of strings to integers and computes their sum. The function should handle any parsing errors by treating unparsable strings as zeros.
Task:
- Write a method
parseToIntthat converts aStringto anIntand returns aFuture[Int]. If parsing fails, it should returnFuture.successful(0). - Implement a method
sumOfStrings(numbers: List[String]): Future[Int]that uses theparseToIntmethod to sum the list of strings treated as integers.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.Try
def parseToInt(s: String): Future[Int] = Future {
Try(s.toInt).getOrElse(0)
}
def sumOfStrings(numbers: List[String]): Future[Int] = {
Future.sequence(numbers.map(parseToInt)).map(_.sum)
}