@ExperimentalCoroutinesApi fun <T> Flow<T>.onCompletion(
    action: suspend FlowCollector<T>.(cause: Throwable?) -> Unit
): Flow<T>

Invokes the given action when the given flow is completed or cancelled, using the exception from the upstream (if any) as cause parameter of action.

Conceptually, onCompletion is similar to wrapping the flow collection into a finally block, for example the following imperative snippet:

try {
    myFlow.collect { value ->
} finally {

can be replaced with a declarative one using onCompletion:

    .onEach { println(it) }
    .onCompletion { println("Done") }

This operator is transparent to exceptions that occur in downstream flow and does not observe exceptions that are thrown to cancel the flow, while any exception from the action will be thrown downstream. This behaviour can be demonstrated by the following example:

flow { emitData() }
    .map { computeOne(it) }
    .onCompletion { println(it) } // Can print exceptions from emitData and computeOne
    .map { computeTwo(it) }
    .onCompletion { println(it) } // Can print exceptions from emitData, computeOne, onCompletion and computeTwo

The receiver of the action is FlowCollector and this operator can be used to emit additional elements at the end of the collection. For example:

flowOf("a", "b", "c")
    .onCompletion { emit("Done") }
    .collect { println(it) } // prints a, b, c, Done