bj4947
bj4947

Reputation: 910

How do I map non-null elements without an assertion in Kotlin?

I am trying to find better way to chain the filter and map operators in Kotlin. What I want to do is to filter the null items before going to the map operator.

I was able to chain them, but the compiler complained about the nullability of my list items.

class Person(val age : String?)

fun foo(age :String){
    // require non-null age
}

The sample usage was:

val list = mutableListOf(Person("3"), Person("2"))

list.filter{ it.age != null }.map{ foo(it.age) }
// The IDE wants me to add !!

So why can't Kotlin infer the nullability? The filtered (all non-null) items passed down to map should had been filtered to ensure that they are non-null.

Upvotes: 1

Views: 1292

Answers (3)

broot
broot

Reputation: 28322

This case may seem easy for a human, but technically speaking it would be really hard for the compiler to understand that after filtering it is a list of people objects, but with different type of the age property than original.

If you don't use a whole people instance at map() stage then I think the easiest would be to do:

list
    .mapNotNull { it.age }
    .map(::foo)

Or, if your foo() can't return nulls:

list.mapNotNull { it.age?.let(::foo) }

But I think this is less readable. Or you can just use !! - it's not that bad if we know what we're doing.

Upvotes: 1

ulou
ulou

Reputation: 5853

You can replace filter and map with one method mapNotNull:

val list2 = list.mapNotNull { it.age }

Upvotes: 4

Henry Twist
Henry Twist

Reputation: 5980

You can use the Iterable<T>.filterNotNull() extension function here which will return a list of the non-nullable type.

In your case, the compiler just isn't advanced enough to smart-cast the filtered list, it would be quite a lot to ask. So if you need to use filter specifically you would have to add an assertion.

Upvotes: 0

Related Questions