```flow { emit(0) emit(1) emit(2) throw Illega...
# coroutines
a
Copy code
flow {
 emit(0)
 emit(1)
 emit(2)
 throw IllegalStateException("some error")
 emit(3)
 emit(4)
}
.catch { e -> println(e)}
.onCompletion { println("complete") }
.launchIn(CoroutineScope(Dispatchers.Default))
Hello, can someone explain is there a way to handle an exception without try-catch code. Now, this exception causes
onCompletion
, but I want to continue working with dataFlow even if an exception appears.
k
If the flow always throws an exception like above, there’s no way around try catching.
Copy code
flow {
 emit(0)
 emit(1)
 emit(2)
 try {  throw IllegalStateException("some error") } catch (e: IllegalStateException) { /* suppress */ }
 emit(3)
 emit(4)
}
If it only happens intermittently, there’s
Flow.retry
a
That’s sad :(
k
What exactly is your use case? Trying to limp along if exceptions occur in a flow would break structured concurrency. I think it’s the opposite of sad.
👍 2
a
datflow .filter(complexLogic) .filter(complexLogic2) .map(complexLogic3) .map(complexLogic4) .catch(logIfError) .onEach(ifAllAboveOkSendMessageToAnotherService) .launchIn(myCoroutineScope) Any of complexLogicN may throw an exception, it’s ok for me, I just to need to log it. But if it’s success, then i need to send a message to another service
k
This isn’t a problem with Flow, this is a problem with your complex logic. Exceptions are generally meant to stop everything, not to be used as control flow.
f
You can do it like this: https://pl.kotl.in/QKHkKOYnY
😭 1
👎 2
k
You should do something like this instead.
Copy code
fun complexLogic(logger: Logger) = try {
  complex()
} catch(e: SomeException) {
  logger.log(e)
}
stop the functions themselves from throwing exceptions in your flow. @franztesca’s solution would work but it’s not exactly easy to follow!
r
Another approach that somewhat automates all the catching: https://discuss.kotlinlang.org/t/flow-how-to-retry-or-skip-single-element-on-error/15755
💚 1
1
f
I guess that is not something one would want to do in their codebase, but it's the answer to the question. No matter what, there is no way to execute the code after a throw statement, it's one way only.
👍 1
r
Whatever approach you settle on just make really sure you don’t accidentally ignore a CancellationException maskot angry
☝️ 2
👍 1
k
Note that the above
mapWithTryCatch
will only catch exception from the lamba
action
you pass in; it won’t catch upstream exceptions.
a
yep, understood. Thank you all
p
An OK pattern for “restartable throwing flow” is
Copy code
outerFlow
  .flatMapLatest { 
    innerFlowThatThrows
      .catch { something }
  }
Outer flow is still alive after inner flow throws, and restarts inner flow after every new emission