Search code examples
kotlinkotlin-null-safety

Change nullability of list elements without copying list


I'm calling a third-party function (which I can't change) which returns a list of nullable elements (List<Int?>), but I know for certain that all elements are non-null. I then want to pass this list to another third-party function, which takes a list of non-null elements (List<Int>). If I cast it, as I do in the code below, I get a warning. If I use filterNotNull it copies the list unnecessarily. How can I avoid copying the list and also not triggering an unchecked cast warning?

fun foo() {
    val a = bar(includeNullElements = false)
    baz(a.map { it!! })     // Undesirable to copy large list
    baz(a.filterNotNull())  // Undesirable to copy large list
    baz(a as List<Int>)     // Gives unchecked cast warning
}

/**
 * This function comes from a library that I can't change.
 * Returns a very large list of elements known to be non-null,
 * but unfortunately are typed as nullable.
 */
fun bar(includeNullElements: Boolean): List<Int?> = TODO()

/**
 * This function comes from a library that I can't change.
 * Takes a list of non-null elements.
 */
fun baz(a: List<Int>) {
    println(a)
}


Solution

  • What you can do if you absolutely don't want to copy the list, is that you cast the list to a non-nullable list, you suppress the warning for an unchecked cast, but you don't do that in an unsafe way, because you check the list before casting:

    fun <T: Any> List<T?>.asNonNullable(): List<T> {
        if(any { it == null }) throw IllegalArgumentException("unexpected null element")
        @Suppress("UNCHECKED_CAST")
        return this as List<T>
    }