99package kotlinx.coroutines.flow
1010
1111import kotlinx.coroutines.flow.internal.*
12+ import kotlinx.coroutines.internal.Symbol
1213import kotlin.jvm.*
1314
1415/* *
@@ -47,33 +48,39 @@ public suspend inline fun <T, R> Flow<T>.fold(
4748}
4849
4950/* *
50- * The terminal operator, that awaits for one and only one value to be published .
51+ * The terminal operator that awaits for one and only one value to be emitted .
5152 * Throws [NoSuchElementException] for empty flow and [IllegalStateException] for flow
5253 * that contains more than one element.
5354 */
5455public suspend fun <T > Flow<T>.single (): T {
5556 var result: Any? = NULL
5657 collect { value ->
57- if (result != = NULL ) error( " Expected only one element" )
58+ require (result == = NULL ) { " Flow has more than one element" }
5859 result = value
5960 }
6061
61- if (result == = NULL ) throw NoSuchElementException (" Expected at least one element" )
62- @Suppress(" UNCHECKED_CAST" )
62+ if (result == = NULL ) throw NoSuchElementException (" Flow is empty" )
6363 return result as T
6464}
6565
6666/* *
67- * The terminal operator, that awaits for one and only one value to be published .
68- * Throws [IllegalStateException] for flow that contains more than one element .
67+ * The terminal operator that awaits for one and only one value to be emitted .
68+ * Returns the single value or `null`, if the flow was empty or emitted more than one value .
6969 */
70- public suspend fun <T : Any > Flow<T>.singleOrNull (): T ? {
71- var result: T ? = null
72- collect { value ->
73- if (result != null ) error(" Expected only one element" )
74- result = value
70+ public suspend fun <T > Flow<T>.singleOrNull (): T ? {
71+ var result: Any? = NULL
72+ collectWhile {
73+ // No values yet, update result
74+ if (result == = NULL ) {
75+ result = it
76+ true
77+ } else {
78+ // Second value, reset result and bail out
79+ result = NULL
80+ false
81+ }
7582 }
76- return result
83+ return if ( result == = NULL ) null else result as T
7784}
7885
7986/* *
@@ -112,7 +119,7 @@ public suspend fun <T> Flow<T>.first(predicate: suspend (T) -> Boolean): T {
112119 * The terminal operator that returns the first element emitted by the flow and then cancels flow's collection.
113120 * Returns `null` if the flow was empty.
114121 */
115- public suspend fun <T : Any > Flow<T>.firstOrNull (): T ? {
122+ public suspend fun <T > Flow<T>.firstOrNull (): T ? {
116123 var result: T ? = null
117124 collectWhile {
118125 result = it
@@ -122,10 +129,10 @@ public suspend fun <T : Any> Flow<T>.firstOrNull(): T? {
122129}
123130
124131/* *
125- * The terminal operator that returns the first element emitted by the flow matching the given [predicate] and then cancels flow's collection.
132+ * The terminal operator that returns the first element emitted by the flow matching the given [predicate] and then cancels flow's collection.
126133 * Returns `null` if the flow did not contain an element matching the [predicate].
127134 */
128- public suspend fun <T : Any > Flow<T>.firstOrNull (predicate : suspend (T ) -> Boolean ): T ? {
135+ public suspend fun <T > Flow<T>.firstOrNull (predicate : suspend (T ) -> Boolean ): T ? {
129136 var result: T ? = null
130137 collectWhile {
131138 if (predicate(it)) {
0 commit comments