Работал ли с CoroutineExceptionHandler

Ответ

Да, работал. CoroutineExceptionHandler используется для обработки необработанных исключений в корутинах. Он добавляется в контекст корутины через CoroutineScope или launch/async.

Пример:

val handler = CoroutineExceptionHandler { _, exception ->  
    println("Caught $exception")  
}  

val scope = CoroutineScope(Job() + handler)  
scope.launch {  
    throw RuntimeException("Failed!")  
}  

Нюансы:

  • Работает только для необработанных исключений (не перехваченных try/catch).
  • В async исключение не выбросится сразу — нужно вызывать await().
  • Не сработает для SupervisorJob, если ошибка в дочерней корутине.
  • Лучше логировать или уведомлять пользователя, а не подавлять ошибки.

Ответ 18+ 🔞

А, блядь, про CoroutineExceptionHandler спрашиваешь? Ну да, работал, конечно, ебать мои старые костыли. Эта штука — как последний патрон, когда в корутине всё пошло по пизде и исключение никто не поймал. Просто добавляешь её в контекст через CoroutineScope или прямо в launch.

Вот, смотри, как это выглядит, простой пример:

val handler = CoroutineExceptionHandler { _, exception ->  
    println("Caught $exception")  
}  

val scope = CoroutineScope(Job() + handler)  
scope.launch {  
    throw RuntimeException("Failed!")  
}  

Всё, типа, приехали. Запустил корутину, она там упала с криком «Failed!», а хендлер этот, как верный пёс, подобрал этот пиздец и вывел в консоль. Удобно, казалось бы.

Но тут, чувак, подвохов — овердохуища, будь осторожен.

Первое и главное: этот хендлер — не волшебная таблетка. Он ловит только то, что никто не поймал. То есть если ты внутри корутины обернул код в try/catch и тихо схавал исключение, то хендлеру нихуя не достанется. Он работает на последнем рубеже, когда всё уже накрылось медным тазом и ошибка вылетает наверх.

Второе: с async вообще отдельная песня. Если ты запускаешь через async, то исключение не вылетает сразу, как из launch. Оно притаится внутри этого Deferred и вылезет наружу, только когда ты вызовешь await(). Так что хендлер тут не сработает, пока ты не начнёшь ждать результат. Подозрение ебать чувствую к этой асинхронности.

Третье, про SupervisorJob: тут вообще ёперный театр. Если у теска SupervisorJob и падает одна дочерняя корутина, то остальные-то продолжают работать. Так вот, хендлер, который висит на самом скопе, не увидит ошибку из этой упавшей дочерней корутины! Она изолируется. Чтобы её поймать, нужно вешать хендлер прямо на контекст этой конкретной корутины, которая запускается. Иначе — пиши пропало.

И главный совет, который я дам: не используй эту штуку, чтобы просто заткнуть дыру и забыть. Это не для того, чтобы подавлять ошибки. Лучше логируй их, чтобы понимать, где косяк, или уведомляй пользователя, что что-то пошло не так. А то получится — в продакшене всё падает, а в логах тишина, потому что хендлер всё схоронил. Доверия ебать ноль к такой тишине.