Ответ
В Kotlin Flow исключения обрабатываются с помощью операторов catch и onCompletion.
Пример:
flow {
emit(1)
throw RuntimeException("Error!")
}
.catch { e ->
println("Caught exception: $e")
emit(-1) // можно эмитить fallback значение
}
.collect { value ->
println("Received: $value")
}
Нюансы:
catchперехватывает исключения выше по цепочке, но не ниже.onCompletionвызывается в любом случае (успех/ошибка), но не перехватывает исключения.- Для глобальной обработки можно использовать
CoroutineExceptionHandlerв корутине.
Если нужно перехватывать исключения в collect, оберни вызов в try-catch.
Ответ 18+ 🔞
Эй, смотри-ка, народ подтянулся! Давайте про Flows поговорим, а то у некоторых с исключениями там ёперный театр начинается, как в цирке с конями.
Вот представь: у тебя есть Flow, он эмитит данные, как миленький, а потом — бац! — RuntimeException("Error!"). И всё, пиздец, поток накрылся медным тазом, коллектор плачет, корутина дохнет. Не, ну так-то не пойдёт.
Спасение — операторы catch и onCompletion. Это как два охранника у двери в клуб: один ловит буянов (catch), а второй просто фиксирует, кто вошёл и кто вышел, даже если его побили (onCompletion).
Смотри, как catch работает, это просто песня:
flow {
emit(1)
throw RuntimeException("Error!")
}
.catch { e ->
println("Поймал исключение: $e") // Ёб твою мать, наконец-то!
emit(-1) // Можно выдать запасное значение, типа "всё пропало, но держи -1"
}
.collect { value ->
println("Принял: $value")
}
Запустишь — получишь "Принял: 1", а потом "Поймал исключение: java.lang.RuntimeException: Error!" и следом "Принял: -1". Поток не сдох, живой, коллектор доволен. Красота!
А теперь нюансы, блядь, без них никуда:
catch— он как хитрая жопа, ловит только то, что вылетело выше по цепочке, до него. Если ошибка случится в самомcollectили в каком-нибудьmapпослеcatch— всё, приехали, не поймает. Доверия к нему, блять, ноль, если не знать этого правила.onCompletion— это такой себе аккуратный бухгалтер. Его вызовут в любом случае: и если поток успешно завершился, и если его ёбнуло ошибкой. Он тебе скажет: "Всё, брат, поток закрывается. Вот причина, если была (cause)". Но! Он не перехватывает исключения. Он просто констатирует факт. Хочешь обработать — тебе вcatch.- Если тебе надо глобально всё отлавливать, на уровне всей этой движухи, можно прикрутить
CoroutineExceptionHandlerк корутине, в которой всё это крутится. Это как поставить сетку над всем цирковым манежем.
И главный лайфхак, который многие забывают, а потом охуевают: если тебе нужно ловить косяки прямо в collect {...}, просто оберни этот блок в старый добрый try-catch. Да, просто и грубо, но работает.
try {
myFlow.collect { value ->
// Тут тоже может вылететь какая-нибудь залупа конская
riskyOperation(value)
}
} catch (e: Exception) {
println("Ну всё, пизда рулю: $e")
}
Вот и вся магия. Главное — понять, кто (catch или onCompletion) за что отвечает, а не тыкать их наугад, как слепой котёнок. Тогда и волнение, блять, уйдёт, и потоки будут как шёлковые.