Gre*_*reg 9 kotlin kotlin-coroutines kotlin-flow
我无法理解catch运算符在 kotlin 中的工作原理Flow。
这是捕获文档
问题:
catch在Flow遇到异常时继续,而不是完成?catch似乎改变了行为。为什么我不能将catch运算符放在链的末尾以看到相同的结果?在我的示例中,只有当我将其放置在 BEFORE 之前,它才会执行onEach。第一个例子,放置catchBEFORE onEach:
fun main() {
// Flow of lambdas that return a String (or throw an Exception)
flowOf<() -> String>({ "Hello " }, { error("error") }, { "World" })
// Map to the result of the invocation of the lambda
.map { it() }
// This line will emit the error String, but then the flow completes anyway.
// I would expect the flow to continue onto "World"
.catch { emit("[Exception caught] ") }
.onEach { println(it) }
.launchIn(GlobalScope)
}
Run Code Online (Sandbox Code Playgroud)
实际结果:
Hello [Exception caught]
预期结果:
Hello [Exception caught] World
第二个例子,放置catchAFTER onEach:
fun main() {
// Flow of lambdas that return a String (or throw an Exception)
flowOf<() -> String>({ "Hello " }, { error("error") }, { "World" })
// Map to the result of the invocation of the lambda
.map { it() }
.onEach { println(it) }
// I would expect this catch to emit, but it never gets here.
.catch { emit("[Exception caught] ") }
.launchIn(GlobalScope)
}
Run Code Online (Sandbox Code Playgroud)
实际结果:
Hello
预期结果:
Hello [Exception caught] World
或者,由于onEach发生在 的发射之前catch,因此catch的发射将被忽略?在这种情况下,预期的输出将是这样的?:
Hello World
Ale*_*exT 15
对我来说,解释你正在做什么的最简单方法是将其简化为同步代码。你基本上是这样做的:
fun main() {
val list = listOf("Hello", "error", "World")
try {
for (s in list) {
if (s == "error") error("this is the error message here")
println(s)
}
} catch (e: Exception) {
println("the exception message is: ${e.localizedMessage}")
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
Hello
the exception message is: this is the error message here
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,异常被捕获了,但是它不能阻止循环的停止for。与异常停止函数的方式相同map。
Flow.catch 将捕获异常并阻止其传播(除非您再次抛出它),但它无法后退一步(回到地图乐趣)并告诉它神奇地从下一个元素所在的位置重新开始或等等
如果你想要这样,你需要在乐趣try/catch中加入一个正常的东西.map。所以它会是:
fun main() {
val list = listOf("Hello", "error", "World")
for (s in list) {
try {
if (s == "error") error("this is the error message here")
println(s)
} catch (e: Exception) {
println("the exception message is: ${e.localizedMessage}")
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
Hello
the exception message is: this is the error message here
World
Run Code Online (Sandbox Code Playgroud)
通常使用的方法Flow.catch是捕获会阻止下一步的异常,例如如果您有:
//pseudo
flow
.map{/*code*/}
.filterNotNull()
.doSomethingRisky() //this can throw an exception
.catch {} //do something about it
.doSomethingElse()
Run Code Online (Sandbox Code Playgroud)
在这种情况下,即使doSomethingRisky抛出异常,流程仍然会到达doSomethingElse. 这或多或少都是利用了Flow.catch.