Kotlin 调用flow.single()时何时引发NosTouchElementException
假设我有这样一个API:Kotlin 调用flow.single()时何时引发NosTouchElementException,kotlin,kotlin-coroutines,kotlin-flow,Kotlin,Kotlin Coroutines,Kotlin Flow,假设我有这样一个API: interface Foo { val barFlow: Flow<Bar> } 根据single的文档,如果流为空,则可以抛出NoTouchElementException。然而,这让我很困惑,因为流上的终端操作将“等待”流的元素被释放。那么对single的调用如何知道流中没有元素呢?也许一个元素还没有发射出来 我的意思是在引擎盖下,对single的调用是在执行检查之前收集源流。因此,在执行null检查之前,必须至少发出1项,以便null检查永远不
interface Foo {
val barFlow: Flow<Bar>
}
根据single
的文档,如果流为空,则可以抛出NoTouchElementException
。然而,这让我很困惑,因为流上的终端操作将“等待”流的元素被释放。那么对single
的调用如何知道流中没有元素呢?也许一个元素还没有发射出来
我的意思是在引擎盖下,对single
的调用是在执行检查之前收集源流。因此,在执行null检查之前,必须至少发出1项,以便null检查永远不会成功,并且永远不会抛出NoTouchElementException
(对于流为不可为null的类型的情况)
那么,NoSuchElementException
是否只可能是可空类型的流
以下是单个
的源代码:
/**
* The terminal operator, that awaits for one and only one value to be published.
* Throws [NoSuchElementException] for empty flow and [IllegalStateException] for flow
* that contains more than one element.
*/
public suspend fun <T> Flow<T>.single(): T {
var result: Any? = NULL
collect { value ->
if (result !== NULL) error("Expected only one element")
result = value
}
if (result === NULL) throw NoSuchElementException("Expected at least one element")
@Suppress("UNCHECKED_CAST")
return result as T
}
/**
*终端运算符,它只等待一个值被发布。
*为空流抛出[NoTouchElementException],为流抛出[IllegalStateException]
*包含多个元素的。
*/
public suspend fun Flow.single():T{
变量结果:有吗?=NULL
收集{值->
if(result!==NULL)错误(“预期只有一个元素”)
结果=值
}
if(result==NULL)抛出NoTouchElementException(“至少应包含一个元素”)
@抑制(“未选中的_CAST”)
将结果返回为T
}
当流在不发射单个元素的情况下完成其发射时,将引发NoTouchElementException
。我现在可以想到的一个例子是,当您需要将集合转换为流源时。如果该集合是空的,并且您在该流上调用single
,您将得到一个NoTouchElementException
这个例子可能看起来很荒谬,但你明白了这一点:
val emptyListFlow = emptyList<Int>().asFlow()
launch {
val data = emptyListFlow.single()
}
val-emptyListFlow=emptyList().asFlow()
发射{
val data=emptyListFlow.single()
}
当流在不发射单个元素的情况下完成其发射时,将引发NoTouchElementException
。我现在可以想到的一个例子是,当您需要将集合转换为流源时。如果该集合是空的,并且您在该流上调用single
,您将得到一个NoTouchElementException
这个例子可能看起来很荒谬,但你明白了这一点:
val emptyListFlow = emptyList<Int>().asFlow()
launch {
val data = emptyListFlow.single()
}
val-emptyListFlow=emptyList().asFlow()
发射{
val data=emptyListFlow.single()
}
那么一个流有一个终点了吗?“我还以为这是一条无穷无尽的溪流呢。”汤马斯科:当然,它可能会结束。一旦完成了调用终端的协同程序,终端操作符将在下一行继续执行。那么流就结束了吗?“我还以为这是一条无穷无尽的溪流呢。”汤马斯科:当然,它可能会结束。一旦完成了调用终端的协同程序,终端操作符将在下一行继续执行。