Skip to content

Commit 76f157f

Browse files
qwwdfsadpablobaxter
authored andcommitted
Introduce Flow.last and Flow.lastOrNull operators (Kotlin#2662)
Fixes Kotlin#2246
1 parent 5c3b008 commit 76f157f

File tree

3 files changed

+72
-0
lines changed

3 files changed

+72
-0
lines changed

kotlinx-coroutines-core/api/kotlinx-coroutines-core.api

+2
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,8 @@ public final class kotlinx/coroutines/flow/FlowKt {
965965
public static final fun fold (Lkotlinx/coroutines/flow/Flow;Ljava/lang/Object;Lkotlin/jvm/functions/Function3;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
966966
public static final fun forEach (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)V
967967
public static final fun getDEFAULT_CONCURRENCY ()I
968+
public static final fun last (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
969+
public static final fun lastOrNull (Lkotlinx/coroutines/flow/Flow;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
968970
public static final fun launchIn (Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/Job;
969971
public static final fun map (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;
970972
public static final fun mapLatest (Lkotlinx/coroutines/flow/Flow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/Flow;

kotlinx-coroutines-core/common/src/flow/terminal/Reduce.kt

+25
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,28 @@ public suspend fun <T> Flow<T>.firstOrNull(predicate: suspend (T) -> Boolean): T
144144
}
145145
return result
146146
}
147+
148+
/**
149+
* The terminal operator that returns the last element emitted by the flow.
150+
*
151+
* Throws [NoSuchElementException] if the flow was empty.
152+
*/
153+
public suspend fun <T> Flow<T>.last(): T {
154+
var result: Any? = NULL
155+
collect {
156+
result = it
157+
}
158+
if (result === NULL) throw NoSuchElementException("Expected at least one element")
159+
return result as T
160+
}
161+
162+
/**
163+
* The terminal operator that returns the last element emitted by the flow or `null` if the flow was empty.
164+
*/
165+
public suspend fun <T> Flow<T>.lastOrNull(): T? {
166+
var result: T? = null
167+
collect {
168+
result = it
169+
}
170+
return result
171+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.coroutines.flow
6+
7+
import kotlinx.coroutines.*
8+
import kotlin.test.*
9+
10+
class LastTest : TestBase() {
11+
@Test
12+
fun testLast() = runTest {
13+
val flow = flowOf(1, 2, 3)
14+
assertEquals(3, flow.last())
15+
assertEquals(3, flow.lastOrNull())
16+
}
17+
18+
@Test
19+
fun testNulls() = runTest {
20+
val flow = flowOf(1, null)
21+
assertNull(flow.last())
22+
assertNull(flow.lastOrNull())
23+
}
24+
25+
@Test
26+
fun testNullsLastOrNull() = runTest {
27+
val flow = flowOf(null, 1)
28+
assertEquals(1, flow.lastOrNull())
29+
}
30+
31+
@Test
32+
fun testEmptyFlow() = runTest {
33+
assertFailsWith<NoSuchElementException> { emptyFlow<Int>().last() }
34+
assertNull(emptyFlow<Int>().lastOrNull())
35+
}
36+
37+
@Test
38+
fun testBadClass() = runTest {
39+
val instance = BadClass()
40+
val flow = flowOf(instance)
41+
assertSame(instance, flow.last())
42+
assertSame(instance, flow.lastOrNull())
43+
44+
}
45+
}

0 commit comments

Comments
 (0)