对于流,onComplete和try/final之间有什么区别?



关于 Flow 的文档描述了为什么emit永远不应该在 try/catch 块中运行:

实现从不捕获或处理下游流中发生的异常。从实现的角度来看,这意味着对emitemitAll的调用永远不应该被包装到try { ... } catch { ... }块中。流中的异常处理应使用catch运算符执行,它旨在仅捕获来自上游流的异常,同时传递所有下游异常...相同的推理可以应用于作为 finally 块的声明性替换的onCompletion运算符。

但是,onCompletion的文档指定

catch不同,此运算符报告上游和下游发生的异常,并观察为取消流而引发的异常。当且仅当流已成功完成时,异常为空。

那么:如果对下游异常不透明,那么使用finallyonCompletion有什么区别? 在许多用例中,onCompletion非常难以使用,特别是任何基于"资源尝试"的流,其中流中没有传递状态。

具体来说,我会对一段演示行为差异的代码感到满意。

使用两者后我的结论是:

  • 当清理代码需要知道流是成功还是失败时,onCompletion很有用
  • 当您始终希望运行完全相同的清理而不管流是成功还是失败时,try/finally非常有用

这是因为onCompletion接收失败原因作为参数,或者null流是否正常完成,没有异常。

myFlow.onCompletion { failure ->
if (failure == null) println("Success") else println("Failure")
}

从文档中:

onCompletion的主要优点是lambda的可为空的Throwable参数,可用于确定流收集是正常完成还是异常完成。

https://kotlinlang.org/docs/flow.html#declarative-handling

try/catch实现同样的事情有点冗长(实际上需要一个catch而不是finally

try {
collect()
} catch (t: Throwable) {
println("Failure")
throw t
}
println("Success")

你提到了尝试资源。我认为重要的是要注意流生成器中的try/finally与流收集器中的try/finally之间的区别。前者对于关闭流使用的资源很有用;后者更类似于onCompletion.

上面的示例显示了流收集器中的try/catch。如果您不需要知道它是成功还是失败,它可以很容易地替换为try/finally。另一方面,在流生成器中使用finally进行清理将如下所示:

flow {
val myResource = openResource()
try {
myResource.values.forEach { emit(it) }
} finally {
myResource.cleanup()
}
}

实际上,您可能会使用use而不是try/finally来做到这一点。正如您所指出的,这不是您可以使用onCompletion(或流收集器中的try/catch/finally)执行的操作,因为它依赖于流构建器内部的状态。我认为流的一大好处是,流的每个阶段都可以以这种方式封装其设置和清理。

实际上,onCompletion将上面的流收集器和流生成器示例组合在一起。这是因为在流无异常的情况下终止的情况下,onCompletion可以发出新值。当流失败并出现异常时,它无法发出值这一事实是一种人为的限制,当您查看源代码时,实际上会使实现复杂化。

通过编写我们自己的流运算符,我们可以克服这个约束:

fun <T> Flow<T>.finally(block: suspend FlowCollector<T> -> Unit) {
try {
emitAll(this@finally)
} finally {
block(t)
}
}

使用上述运算符,someFlow.finally { emit(...) }将始终发出一个新值,即使流失败并出现异常也是如此。我不确定它是否违反了禁止用try/catch包裹emit的规定,但这感觉不是一个特别好的主意。

正如您所说,onCompletionfinally都将在上游异常、下游异常和正常完成的情况下运行。从这个意义上说,它们在行为上没有差异(据我所知),所以我无法举出一个例子来展示差异。

一个补充是onCompletion的lambda可以访问一个FlowCollector,该可以将更多的元素emit()到下游流(当没有发生异常时)。

我想除此之外,这里唯一的区别是风格。就像.filter{}一样 和if(condition) emit(it)一样.

最新更新