结合kotlin流结果

问题描述

我想知道是否有一种干净的方法可以在 Kotlin 中启动一系列流,然后在解决它们之后,根据它们是否成功执行进一步的操作

例如,我需要从数据库中读取所有整数(将它们返回到流中),检查它们是否针对外部 API 是偶数还是奇数(也返回流),然后从数据库删除奇数

代码中它会是这样的

fun findEven() {
   db.readIntegers()
      .map { listofInt ->
          listofInt.asFlow()
             .flatMapMerge { singleInt ->
                httpClient.apiCalltocheckForOddity(singleInt)
                   .catch {
                      // API failure when number is even
                   }
                   .map {
                      // API success when number is odd
                      db.remove(singleInt).collect()
                   }
             }.collect()
      }.collect()
}

但我在这代码中看到的问题是访问并行完成的 DB 删除条目,我认为更好的解决方案是运行所有 API 调用并在某处收集所有失败和成功的内容,所以要只能在数据库中进行一次批量插入,而不是让多个协程自己做

解决方法

在我看来,在 mapfilter 等中产生副作用是一种反模式。像从数据库中删除项目这样的副作用应该是一个单独的步骤({{ 1}} 在 Flow 的情况下,而 collect 在 List 的情况下)为清楚起见。

嵌套流也有点复杂,因为您可以直接将列表修改为 List。

我认为您可以这样做,假设 API 一次只能检查一项。

forEach

并行版本,如果 API 调用返回参数。 (By the way,Kotlin APIs should not throw exceptions on non-programmer errors)。

suspend fun findEven() {
    db.readIntegers()
            .map { listOfInt ->
                listOfInt.filter { singleInt ->
                    runCatching {
                        httpClient.apiCallToCheckForOddity(singleInt)
                    }.isSuccess
                }
            }
            .collect { listOfOddInt ->
                db.removeAll(listOfOddInt)
            }
}