#kotlin #kotlin-coroutines
Вопрос:
У меня есть что-то вроде
listOf(
getItem1Async(),
getItem2Async(), //error
getItem3Async()
).awaitAl
любая из функций может получить исключение, но поскольку они возвращают отложенное, исключение не обрабатывается до вызова функции await (). Я хочу, например, если getItem2Async завершится неудачно, чтобы создание моего списка не завершилось неудачно, но чтобы получить значение по умолчанию или нулевое значение и сохранить успешные вызовы.
Я просматривал документацию и не мог понять, как использовать ожидание в списке отложенных для возврата элементов без исключений. Я нашел кое-что о сопрограммном обработчике, но не могу вернуть значение null или значение по умолчанию, а также я читал о задании руководителя, но я не уверен, что это правильный инструмент или я должен использовать другой.
Комментарии:
1. Вам нужно будет поместить их в их собственную область сопрограммы с помощью пользовательского обработчика ошибок.
Ответ №1:
Во-первых, нам нужно использовать supervisorScope(), чтобы разбитые дочерние сопрограммы не влияли на другие сопрограммы. Затем мы можем использовать функции Deferred.getCompleted(), Deferred.getCompletionExceptionOrNull() или аналогичные функции для получения результата:
suspend fun main() {
supervisorScope {
listOf(
async { "hello" },
async { check(false) },
async { "world" },
)
}.map { it.getCompletedOrNull() }
.forEach(::println)
}
@OptIn(ExperimentalCoroutinesApi::class)
fun <T> Deferred<T>.getCompletedOrNull() = if (isCancelled) null else getCompleted()
Комментарии:
1.
getCompleted()
переосмысливает любое исключение, отличное от исключения CancellationException, поэтому, возможно, его следует завернуть:runCatching { getCompleted() }.getOrNull()
.2. Хм… не
isCancelled == false
означает ли это, что сопрограмма удалась? НазваниеisCancelled
немного вводит в заблуждение, потому что сбои в сопрограммах считаются отменами. Кроме того, если бы это было так , то я считаю, что приведенный выше код должен быть брошенmap()
, но на самом деле он возвращает значение null для второго элемента.3. Вы правы насчет такого поведения. Я ошибочно полагал, что «отменено» и «завершено» являются взаимоисключающими противоположностями, и что отмена предназначена исключительно для исключений отмены.
4. Честно говоря, API
Job
/Deferred
кажется мне неестественным. Здесь нет ничего простогоisSucceeded
, но вместо этого нам нужно проверитьisCompleted
иisCancelled
. НетgetCompletedOrNull()
, но естьgetCompletionExceptionOrNull()
. Это сбивает с толку. @Tenfour04