Kotlin: eliminate nulls from a List (or other functional transformation)
Asked Answered
A

3

39

Problem

What is the idiomatic way of working around this limitation of the null-safety in the Kotlin type system?

val strs1:List<String?> = listOf("hello", null, "world")

// ERROR: Type Inference Failed: Expected Type Mismatch:
// required: List<String>
// round:    List<String?>
val strs2:List<String> = strs1.filter { it != null }

This question is not just about eliminating nulls, but also to make the type system recognize that the nulls are removed from the collection by the transformation.

I'd prefer not to loop, but I will if that's the best way to do it.

Work-Around

The following compiles, but I'm not sure it's the best way to do it:

fun <T> notNullList(list: List<T?>):List<T> {
    val accumulator:MutableList<T> = mutableListOf()
    for (element in list) {
        if (element != null) {
            accumulator.add(element)
        }
    }
    return accumulator
}
val strs2:List<String> = notNullList(strs1)
Ayeshaayin answered 22/7, 2016 at 21:28 Comment(0)
O
90

You can use filterNotNull

Here is a simple example:

val a: List<Int?> = listOf(1, 2, 3, null)
val b: List<Int> = a.filterNotNull()

But under the hood, stdlib does the same as you wrote

/**
 * Appends all elements that are not `null` to the given [destination].
 */
public fun <C : MutableCollection<in T>, T : Any> Iterable<T?>.filterNotNullTo(destination: C): C {
    for (element in this) if (element != null) destination.add(element)
    return destination
}
Obliterate answered 22/7, 2016 at 21:30 Comment(4)
Sweet! Doh! Why didn't I see that? :-)Ayeshaayin
if you are creating the list you can also use listOfNotNullDudley
I get a Useless call on a collection type warning. Called over a Mutable list<Strings>Semicolon
@Semicolon It is useless, as your list doesn't contain any nulls. It would be a List<String?> otherwise. (Notice the "?")Sewellyn
E
2

you can also use

mightContainsNullElementList.removeIf { it == null }
Estep answered 29/3, 2019 at 11:57 Comment(2)
Please explain that further - what does that line do, and why exactly does it solve the given problem?Falsify
@NicoHaase Actually this code speaks for itself. it's quite understandableConjunctive
E
0
val strs1 = listOf("hello", null, "world") // [hello, null, world]
val strs2 = strs1.filter { !it.isNullOrBlank() } // [hello, world]
Enquire answered 26/4, 2021 at 6:5 Comment(1)
Please add some explanation to your answer such that others can learn from itFalsify

© 2022 - 2024 — McMap. All rights reserved.