You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SharedFlow不存在指定元素时抛出NoSuchElementException

解决SharedFlow等待不存在元素时持续挂起的问题

问题分析

你的代码中使用firstOrNull()会导致:当SharedFlow中没有匹配目标元素,且流未进入完成状态时,会一直挂起等待新元素。而默认的MutableSharedFlow在未调用close()前永远不会完成,所以等待不存在的元素时会无限挂起。

解决方案

要实现"元素不存在时抛出NoSuchElementException"的需求,需要做两处关键修改:

1. 让SharedFlow在发射完所有状态后进入完成状态

在填充状态的emitStates()函数末尾调用close(),标记流已结束,不再发射新元素:

private suspend fun emitStates() {
    _sharedFlow.emit("START")
    delay(100)
    _sharedFlow.emit("FIRST")
    delay(100)
    _sharedFlow.emit("SECOND")
    delay(100)
    _sharedFlow.emit("ENDING")
    delay(100)
    _sharedFlow.emit("IDLE")
    // 标记流完成,不再发射新元素
    _sharedFlow.close()
}

2. 修改awaitState函数,使用first()替代firstOrNull()

first()操作符会在流完成且未找到匹配元素时,自动抛出NoSuchElementException,正好符合你的需求:

private suspend fun awaitState(state: String) {
    _sharedFlow.filter { incomingState -> incomingState == state }
        .onCompletion { Log.d(TAG, "onCompletion()") }
        .onEmpty { Log.d(TAG, "onEmpty()") }
        .first() // 替换firstOrNull(),未找到元素时抛出异常
}

验证效果

  • 成功场景:等待"SECOND"时,流会找到匹配元素并返回,后续代码正常执行。
  • 失败场景:等待"Some"时,流完成后未找到匹配元素,first()会抛出NoSuchElementException,被catch块捕获后执行后续逻辑。

补充说明

如果你不想关闭SharedFlow(比如流需要持续发射新元素),可以结合超时机制实现:在指定时间内未找到元素则抛出异常,示例如下:

private suspend fun awaitState(state: String, timeoutMs: Long = 5000) {
    try {
        withTimeout(timeoutMs) {
            _sharedFlow.filter { incomingState -> incomingState == state }
                .first()
        }
    } catch (e: TimeoutCancellationException) {
        throw NoSuchElementException("State $state not found within timeout")
    }
}

这种方式适用于需要限制等待时长的场景,超时后会将超时异常转换为需求的NoSuchElementException。

内容的提问来源于stack exchange,提问作者Jack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 02:12:50