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

Future

Scala's Future provides a powerful abstraction for working with asynchronous computations. It represents a value that may become available at some point, allowing your program to continue executing while waiting for the result. This is particularly useful for operations that involve IO, database queries, network requests, or any long-running computations.

Here's a simple example demonstrating how to use Scala Futures to perform asynchronous computations:

Setup

First, ensure you have the Scala execution context in scope, as it's needed to execute the futures:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}

Basic Future Usage

The following example shows how to create a future, perform an operation asynchronously, and handle the result once it's available:

// Define a future that simulates a long-running computation
val futureComputation: Future[Int] = Future {
  Thread.sleep(1000) // Simulating a long-running task
  42 // The answer to the ultimate question of life, the universe, and everything
}

// Handling the future's result
futureComputation.onComplete {
  case Success(result) => println(s"Result: $result")
  case Failure(e) => println(s"An error occurred: ${e.getMessage}")
}

Working with Results

Often, you'll want to chain operations on futures or combine them. Here's how to use map, flatMap, and for comprehensions to work with future results:

val futureSquare: Future[Int] = futureComputation.map(x => x * x)

futureSquare.onComplete {
  case Success(square) => println(s"Square of the result: $square")
  case Failure(e) => println(s"Failed to calculate the square: ${e.getMessage}")
}

// Combining futures with for-comprehension
val anotherFutureComputation: Future[Int] = Future {
  Thread.sleep(500) // Another simulated task
  10
}

val combinedResult: Future[Int] = for {
  result1 <- futureComputation
  result2 <- anotherFutureComputation
} yield result1 + result2

combinedResult.onComplete {
  case Success(sum) => println(s"Sum of results: $sum")
  case Failure(e) => println(s"Failed to combine results: ${e.getMessage}")
}

Error Handling

Handling errors with futures can be done using recover or recoverWith methods:

val riskyFuture: Future[Int] = Future {
  throw new RuntimeException("Something went wrong")
}

val recoveredFuture: Future[Int] = riskyFuture.recover {
  case _: RuntimeException => -1
}

recoveredFuture.onComplete {
  case Success(value) => println(s"Recovered value: $value")
  case Failure(e) => println("This should not be printed if recovered properly")
}