0Pricing
Scala for Backend Engineering & Functional Programming · Lezione

Introduzione a Future e Promise

Comprenda i concetti fondamentali di `Future` per i risultati asincroni e di `Promise` per completarli.

Introduzione a Future e Promise è una lezione Scala for Backend Engineering & Functional Programming gratuita su CoddyKit. Questa è la lezione 1 di 3. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Scala for Backend Engineering & Functional Programming, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Scala for Backend Engineering & Functional Programming include 3 lezioni in totale.

Codice asincrono: perché è importante

In programmazione, le attività possono essere eseguite in modo sincrono (una dopo l'altra) o asincrono (le attività possono iniziare senza aspettare che quelle precedenti siano terminate).

La programmazione asincrona è fondamentale per creare applicazioni reattive che non si bloccano in attesa di operazioni lente, come le richieste di rete o le query al database.

Il problema delle chiamate bloccanti

Immagini che il programma debba recuperare dati da Internet. Se questa operazione è bloccante, il programma si fermerà e non farà altro finché i dati non saranno arrivati.

Questo può causare un'interfaccia utente "bloccata" o applicazioni lato server inefficienti. È necessario un modo per eseguire queste attività in background senza interrompere il flusso principale.

Introduzione alle Future di Scala

La Future di Scala è uno strumento potente per la programmazione asincrona. Rappresenta un valore che potrebbe non essere ancora disponibile, ma lo sarà in futuro.

  • La si può immaginare come l'ordinazione di un caffè: si riceve uno scontrino (la Future) e si possono svolgere altre attività mentre il caffè viene preparato.
  • Quando il caffè è pronto, lo scontrino viene "completato" con la bevanda (il risultato).

Creare la prima Future

È possibile creare una Future racchiudendo un calcolo in Future { ... }. Questo calcolo verrà eseguito in un thread separato.

Per pianificare queste attività è necessario un ExecutionContext. Per semplicità, ne useremo uno globale.

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

object Main extends App {
  println("Starting computation...")

  val f: Future[Int] = Future {
    Thread.sleep(1000) // Simulate a long operation
    42
  }

  f.onComplete {
    case Success(value) => println(s"Result: $value")
    case Failure(e) => println(s"Error: ${e.getMessage}")
  }

  println("Computation started, continuing...")
  // Keep main thread alive for a bit to see Future's result
  Thread.sleep(2000)
}

Comprendere ExecutionContext

Un ExecutionContext è essenzialmente un pool di thread in cui vengono eseguiti i calcoli asincroni.

  • Gestisce come e quando vengono eseguite le attività.
  • Per esempi rapidi, si usa spesso scala.concurrent.ExecutionContext.Implicits.global, che fornisce un pool di thread predefinito.
  • Nelle applicazioni reali, è possibile configurare pool di thread specifici per controllare meglio l'uso delle risorse.

Gestire i risultati di Future: onComplete

Il metodo onComplete serve a definire cosa accade quando una Future termina, sia in caso di successo sia in caso di errore.

Riceve una funzione che opera su una scala.util.Try, che può essere Success(value) o Failure(exception).

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

object Main extends App {
  val futureSuccess = Future { 10 / 2 }
  val futureFailure = Future { 10 / 0 }

  futureSuccess.onComplete {
    case Success(result) => println(s"Success: $result")
    case Failure(e) => println(s"Error: ${e.getMessage}")
  }

  futureFailure.onComplete {
    case Success(result) => println(s"Success: $result")
    case Failure(e) => println(s"Error: ${e.getMessage}")
  }

  Thread.sleep(100) // Allow Futures to complete and print
}

Gestori semplificati: Success/Failure

Per i casi più semplici, è possibile usare onSuccess e onFailure per gestire rispettivamente solo i risultati corretti o solo gli errori.

  • onSuccess riceve una funzione per il valore restituito con successo.
  • onFailure riceve una funzione per l'eccezione.
  • Sono metodi di praticità costruiti sopra onComplete.
import scala.concurrent.{Future, ExecutionContext}
import scala.concurrent.ExecutionContext.Implicits.global

object Main extends App {
  val futureValue = Future { "Hello, Scala!" }

  futureValue.onSuccess { case msg => println(s"Got message: $msg") }
  futureValue.onFailure { case e => println(s"Oops, an error: ${e.getMessage}") }

  val futureError = Future { throw new RuntimeException("Something broke!") }

  futureError.onSuccess { case msg => println(s"Got message: $msg") }
  futureError.onFailure { case e => println(s"Oops, an error: ${e.getMessage}") }

  Thread.sleep(100) // Allow Futures to complete and print
}

Che cos'è una Promise di Scala?

Mentre una Future è un segnaposto in sola lettura per un risultato, una Promise è un contenitore scrivibile una sola volta, che può essere completato con un valore o un'eccezione.

  • Una Promise viene usata per completare una Future.
  • Si crea una Promise, si ottiene la Future associata e quindi si completa la Promise quando il risultato è pronto.

Completare una Promise

È possibile completare una Promise usando i metodi success() o failure(). Una volta completata una Promise, anche la Future associata verrà completata.

Il tentativo di completare una Promise più di una volta genera un errore.

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

object Main extends App {
  val p = Promise[String]() // Create a Promise that will hold a String
  val f: Future[String] = p.future // Get the Future associated with the Promise

  f.onComplete {
    case Success(value) => println(s"Future completed with: '$value'")
    case Failure(e) => println(s"Future failed with: ${e.getMessage}")
  }

  // Simulate an async operation completing the promise
  Future {
    Thread.sleep(500)
    p.success("Data fetched successfully!") // Complete the Promise
  }

  println("Promise created, waiting for completion...")
  Thread.sleep(1000) // Keep main thread alive to see Future's result
}

Future e Promise insieme

Future e Promise spesso lavorano insieme. Un modello comune consiste nell'usare una Promise quando è necessario controllare manualmente il completamento di una Future, ad esempio tramite un sistema esterno o un'API meno recente basata sui callback.

Questo consente di racchiudere nel modello Future operazioni asincrone non basate su Future, rendendole compatibili con il codice basato sulle Future.

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

object Main extends App {
  def performLongTask(data: String): Future[String] = {
    val p = Promise[String]()
    // Simulate an external system or callback-based API
    Future {
      Thread.sleep(700)
      if (data == "fail") p.failure(new Exception("Task failed!"))
      else p.success(s"Processed: $data")
    }
    p.future // Return the Future that will be completed by the Promise
  }

  val task1 = performLongTask("input data")
  task1.onComplete { case Success(res) => println(s"Task 1: $res") case Failure(e) => println(s"Task 1: ${e.getMessage}") }

  val task2 = performLongTask("fail")
  task2.onComplete { case Success(res) => println(s"Task 2: $res") case Failure(e) => println(s"Task 2: ${e.getMessage}") }

  Thread.sleep(1500) // Keep main thread alive for results
}

Verifica rapida: Future e Promise a confronto

Quali delle seguenti affermazioni descrivono correttamente i ruoli di Future e Promise in Scala?

Riepilogo: Future e Promise

Ottimo lavoro! In questa lezione sono stati appresi i fondamenti della programmazione asincrona in Scala:

  • Future: un segnaposto per un risultato che sarà disponibile in futuro.
  • Promise: un contenitore a scrittura singola usato per completare manualmente un Future.
  • ExecutionContext: pianifica l'esecuzione delle attività asincrone.
  • Come gestire i risultati di Future usando onComplete, onSuccess e onFailure.

Questi concetti sono gli elementi fondamentali per creare pattern asincroni più complessi!

Domande Frequenti

La lezione «Introduzione a Future e Promise» è gratuita?

Sì — il testo completo di «Introduzione a Future e Promise» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Scala for Backend Engineering & Functional Programming, passa a CoddyKit PRO. Il corso Scala for Backend Engineering & Functional Programming include 3 lezioni in totale.

Cosa imparerò in «Introduzione a Future e Promise»?

Comprenda i concetti fondamentali di `Future` per i risultati asincroni e di `Promise` per completarli. Eserciti Scala for Backend Engineering & Functional Programming con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Scala for Backend Engineering & Functional Programming?

Non è richiesta alcuna esperienza precedente. Scala for Backend Engineering & Functional Programming su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 3.

Quanto tempo richiede la lezione «Introduzione a Future e Promise»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Scala for Backend Engineering & Functional Programming?

Sì. Ogni lezione Scala for Backend Engineering & Functional Programming include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Introduzione a Future e Promise
  2. Composizione delle operazioni asincrone
  3. Gestione degli errori nei Future
← Torna a Scala for Backend Engineering & Functional Programming