带有catch操作符的Kotlin流仍然完成
我很难理解带有catch操作符的Kotlin流仍然完成,kotlin,kotlin-coroutines,kotlin-flow,Kotlin,Kotlin Coroutines,Kotlin Flow,我很难理解catch操作符如何在kotlin流中工作。 问题: 为什么catch的存在不允许流在遇到异常时继续,而不是完成 catch操作符的放置似乎会改变行为。为什么我不能将catch操作符放在链的末尾以查看相同的结果?在我的示例中,仅当我将它放在onEach之前时,它才会执行 第一个示例,将catch放在onEach之前: fun main() { // Flow of lambdas that return a String (or throw an Exception)
catch
操作符如何在kotlin流中工作。
问题:
为什么catch
的存在不允许流在遇到异常时继续,而不是完成
catch
操作符的放置似乎会改变行为。为什么我不能将catch
操作符放在链的末尾以查看相同的结果?在我的示例中,仅当我将它放在onEach
之前时,它才会执行
第一个示例,将catch
放在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)
}
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)
}
实际结果:
Hello
预期结果:
Hello[Exception capture]World
或者,由于onEach
发生在catch
的发射之前,因此catch
的发射将被忽略?在这种情况下,预期的输出为:
helloworld
对于我来说,解释你们在做什么最简单的方法就是将它简化为同步代码。你基本上是这样做的:
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}")
}
}
输出:
Hello
the exception message is: this is the error message here
如您所见,异常被捕获,但它无法阻止for
循环的停止。与该异常停止map
功能的方式相同
Flow.catch将捕获一个异常并阻止它传播(除非您再次抛出它),但它不能后退一步(返回到map fun)并告诉它从下一个元素所在的位置神奇地重新开始
如果你想这样做,你需要在.map
fun里面放一个普通的try/catch
。因此,这将是:
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}")
}
}
}
输出:
Hello
the exception message is: this is the error message here
World
通常使用的Flow.catch
方法是捕获会阻止下一步的异常,例如:
//pseudo
flow
.map{/*code*/}
.filterNotNull()
.doSomethingRisky() //this can throw an exception
.catch {} //do something about it
.doSomethingElse()
在此场景中,即使doSomethingRisky
抛出异常,流仍将到达doSomethingElse
。这或多或少是对流的使用。catch
是和否。如果您有另外两个调用.map
,如果您没有该。catch
,它将永远不会到达后续的两个调用。通过.catch
它将到达它们(但仅限于第一个异常之前可以处理的元素)。但要处理所有元素,您还需要在.map
函数中放入一个正常的try/catch。谢谢您的回答,@Alex。在查看catch文档时,它们提供了一个示例:`flow{emitData()}.map{computeOne(it)}.catch{…}//捕获emitData和computeOne中的异常。map{computeTwo(it)}.collect{process(it)}//从进程和计算中抛出异常`因此,我的map{it()}那个危险的电话会不会被抓到,对吧?顺便说一下,很抱歉格式太糟糕了。第一次如此。。这里有问题:-)注释的格式不能很糟糕,但是“char”确实有助于突出显示内容。顺便说一句,你的问题很好,我会考虑它的高质量,用适当的例子,在你想要达到的目标上非常干净。我见过有2年账户的人情况更糟。(顺便说一句,这条评论和你最近的一条评论很有可能被删除,因为它们是离题的,你知道的)