Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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:

  1. Create a method squareNumber that takes an Int and returns a Future[Int] representing the square of the number.
  2. Implement a method sumOfSquares that accepts a List[Int] and returns a Future[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:

  1. Implement two functions, getTemperature(city: String): Future[Double], that simulate fetching temperature data for each city.
  2. 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:

  1. Write a method parseToInt that converts a String to an Int and returns a Future[Int]. If parsing fails, it should return Future.successful(0).
  2. Implement a method sumOfStrings(numbers: List[String]): Future[Int] that uses the parseToInt method 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)
}