I'd like to check a List<Int?>
for nulls and if no nulls exist, then allow the List to proceed as a List<Int>
, otherwise use an emptyList()
This is what I came up with:
var noNullElements: List<Int> = emptyList()
if (listWithPossibleNullElements.all { it != null }) {
noNullElements = listWithPossibleNullElements as List<Int>
}
//do something with noNullElements list
I'd be shocked if this was the best, most idiomatic way.
Solution
There are many acceptable solutions below, but the one I chose was a combination of the solutions
fun getSafeList(list: List<Int?>): List<Int> =if (null in list) emptyList() else list.requireNoNulls()
Here's a one liner extension function:
inline fun <reified T : Any> Iterable<T?>.filterNoneNull(): Iterable<T>? =
takeIf { null !in it }?.requireNoNulls()
takeIf {}
- a scope function that will return null if the lambda evaluates to falsenull !in it
- use the in
operator function to determine if the list contains null
takeIf {}
returns a non-null value, filterNotNull()
will convert the element type from the nullable T?
to non-null T
Note that it will return null
if the provided Iterable<T?>
contains null
, else List<T>
, in case it's important to differentiate between the provided list being empty, or containing null
. An alternative can be provided using the elvis operator.
Example usage - run in Kotlin Playground:
fun main() {
val listA: List<Int?> = listOf(1, 2, 3, null)
// since listA contains 'null', the result is 'null'
println(listA.filterNoneNull())
// prints: null
// provide an alternative, using the elvis operator
println(listA.filterNoneNull() ?: emptyList<Int>())
// prints: []
val listB: List<Int> = listOf(1, 2, 3)
// since listB does not contain null, the same list is returned
println(listB.filterNoneNull())
// prints: [1, 2, 3]
}
inline fun <reified T : Any> Iterable<T?>.filterNoneNull(): Iterable<T>? =
takeIf { null !in it }?.requireNoNulls()
Note: I edited the example and replaced filterNotNull()
with requireNoNulls()
, as the latter will not instantiate a new list