当生产者发出多个值时 single() 和 first() 终端运算符

Rid*_*dje 3 kotlin kotlin-flow

我只需要收集流发出的两个值中的第一个值。

我有一个返回流量的函数:

fun myFlow = flow {
    try {
        emit(localDataSource.fetchData())
    } catch(e: Exception) { 
        // just skip this error
    }
    emit(remoteDataSource.fetchData(1000, 0))
}
Run Code Online (Sandbox Code Playgroud)

在一种特殊情况下,我只需要第一个发出的值,无论它是来自本地缓存还是远程源。我尝试过这个:

fun getRandomFavoriteItem() = myFlow.first().filter { it.score > 7 }.randomOrNull()

但first()调用总是抛出

java.lang.IllegalStateException:违反了流异常透明度:先前的“emit”调用引发了异常 kotlinx.coroutines.flow.internal.AbortFlowException:流已中止,不再需要元素,但随后尝试发射值。

我尝试过的:

  1. 单身的() -

java.lang.IllegalArgumentException:流有多个元素

  1. take(1).first() -

java.lang.IllegalStateException:违反了流异常透明度:先前的“emit”调用引发了异常 kotlinx.coroutines.flow.internal.AbortFlowException:流已中止,不再需要元素,但随后尝试发射值

  1. 捕获错误,但它并不止于此:
myFlow.catch { e ->
    if (e !is IllegalArgumentException) {
        throw e
    }
}.first().filter { it.score > 7 }.randomOrNull()
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  1. 如果在发出的值超过 1 个的情况下它不起作用,那么使用 first() 的意义何在?如果我知道我的流程仅产生一个值,我可以使用任何其他终端运算符。
  2. 如何避免这些错误以及如何仅收集第一个值而不添加重复代码?

Lou*_*man 5

这不是 中的错误first()。这是您流程中的错误 不允许您以您所拥有的方式吞掉 Flow 中的所有异常。

一些不同的方法可能会在是否检测到该错误方面有所不同,但您必须修复的是如何“跳过”所有异常。考虑仅捕获您关心的特定异常,或者至少确保捕获并重新抛出CancellationException或其子类。