liveBook · Manning

Future

As explained in Kotlin in Action, 2E

A future is an abstraction representing a result that may become available after an asynchronous computation finishes.

A future represents a value that is not available yet but is expected after an asynchronous computation finishes. In Kotlin coroutines, the corresponding value is `Deferred<T>`: `async` starts the computation and returns the deferred handle, while suspending `await()` waits for its result. section 14.6.3

Start two calculations, then await both

`val first = async { slowlyAddNumbers(2, 2) }` and `val second = async { slowlyAddNumbers(4, 4) }` start two independent calculations. Calling `first.await()` and `second.await()` suspends the caller until each result is ready. Because both computations begin before either await, their elapsed time is roughly that of the longer calculation, even on a single thread. section 14.6.3 section 14.6.3

Listing 14.7 Using the async coroutine builder to start a new coroutine
suspend fun slowlyAddNumbers(a: Int, b: Int): Int {
    log("Waiting a bit before calculating $a + $b")
    delay(100.milliseconds * a)
    return a + b
}
 
 
fun main() = runBlocking {
    log("Starting the async computation")
    val myFirstDeferred = async { slowlyAddNumbers(2, 2) }    #1
    val mySecondDeferred = async { slowlyAddNumbers(4, 4) }   #1
    log("Waiting for the deferred value to be available")
    log("The first result: ${myFirstDeferred.await()}")       #2
    log("The second result: ${mySecondDeferred.await()}")     #2
}

Trace the two `async` calls and their later `await()` calls to see the distinction between starting work and waiting for its values. section 14.6.3

Use `async` when independent tasks should start together and their values are needed later. For ordinary sequential work, call suspending functions directly; Kotlin does not require futures or `async`/`await` merely to express asynchronous-looking code. section 14.6.3

A `Deferred` is also a cancellation handle: call `cancel()` to trigger cancellation of the coroutine created by `async`. This parallels a `Job` returned by `launch`, although `async` is intended to calculate an awaitable value rather than run a start-and-forget side effect. section 15.2.1 section 14.6.3

A future-style API can make callback chains flatter, but it introduces wrapped return types and composition operators. With `CompletableFuture`, successive work uses operators such as `thenCompose` and `thenAccept`; coroutine code instead marks functions `suspend` and can retain direct-looking calls when concurrency is unnecessary. section 14.5 section 14.6.3

Handle failures when consuming a deferred result

For an outer coroutine created with `async`, a `CoroutineExceptionHandler` is not invoked for its exception. The consumer of the `Deferred` handles that failure by calling `await()` inside `try`/`catch`. This responsibility differs from a topmost `launch` coroutine, for which the handler can be invoked. section 18.3.1 section 18.6

How Kotlin in Action, 2E covers it

How deep it goes
Defines Deferred, demonstrates async and await timing, and explains cancellation and exception-consumption responsibilities.
Examples
Uses concurrent delayed addition, chained login and user-data loading, cancellation, and an exception thrown beneath async.
What it assumes
Assumes familiarity with asynchronous approaches only for the comparison to callbacks, futures, and reactive streams.
What you can do after
Apply it via Kotlin async and await to run independent tasks concurrently and consume their values or failures.
How it connects
Connects Deferred to Kotlin coroutines, async, await, launch, Job, CompletableFuture, callbacks, and CoroutineExceptionHandler.

Also explained in

Compare how 8 books explain future →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Kotlin in Action, 2E. The section links point to the parts of the book it draws on.