https://kotlinlang.org logo
#flow
Title
# flow
m

Maciek

12/22/2021, 11:50 AM
I'm having troubles understanding the exception handling in the flow. Could someone explain why the throwable completes the flow even with the
catch { }
in the chain? If I'd want to have a infinite flow I must handle the exceptions with
try catch
in the lambdas because flow will close after any exception "leaking" to the stream, right? Or is there a way to do some explicit recover from the exception? Example code, only
0
will be emitted, next emit
1
is lost due to flow completion after exception.
Copy code
flow {
  emit(0)
  emit(1) // this emit is never reached
}
  .onEach { if (it == 0) throw Throwable() }
  .catch { println(it) }
  .collect()
so in order for this code to work as expected I'd have to add
try catch
in the
onEach
e

elizarov

12/22/2021, 4:08 PM
catch
lets you handle the flow exception, but there’s no way to recover from it the way you want. The flow is already dead.
That is, in your code
emit(0)
had already threw an exception and
emit(1)
cannot be ever reached.
m

Maciek

12/22/2021, 4:12 PM
I thought I missed something in the understanding of exception handling. Appreciate the explanation
is this concept of recovery is something that conflicts with the philosophy of coroutines and will never be added to the API or is it something that could be considered? I guess there'd be some scenarios that such API could make the error handling a bit nicer or simpler to write
n

Nick Allen

12/22/2021, 5:07 PM
It's part of the API contract. See "Exception transparency" section of Flow documentation. Flows are not allowed to catch the exceptions that come from emit.
Exceptions are how collectors stop collecting so
Flow
is required to not emit anything else. This is how operators like
first
and
take
work, they throw exceptions inside
collect
and then catch only their own exceptions outside
collect
.
m

Maciek

12/22/2021, 5:18 PM
awesome, thanks a ton for the explanation!
e

expensivebelly

12/23/2021, 2:54 PM
We use
retryWhen
to recover from Exceptions, once it goes past
retryWhen
(if the predicate returns false) then at that point the Flow has completed with an exception (as far as I know) and there is no way to re-subscribe to it