Kotlin: How to work with List casts: Unchecked Cast: kotlin.collections.List<Kotlin.Any?> to kotlin.colletions.List<Waypoint>


2 Answers

In case of generic classes casts cannot be checked because type information is erased in runtime. But you check that all objects in the list are Waypoints so you can just suppress the warning with @Suppress("UNCHECKED_CAST").

To avoid such warnings you have to pass a List of objects convertible to Waypoint. When you're using * but trying to access this list as a typed list you'll always need a cast and this cast will be unchecked.

Question

I want to write a function that returns every item in a List that is not the first or the last item (a via point). The function gets a generic List<*> as input. A result should only be returned if the elements of the list are of the type Waypoint:

fun getViaPoints(list: List<*>): List<Waypoint>? {

    list.forEach { if(it !is Waypoint ) return null }

    val waypointList = list as? List<Waypoint> ?: return null

    return waypointList.filter{ waypointList.indexOf(it) != 0 && waypointList.indexOf(it) != waypointList.lastIndex}
}

When casting the List<*> to List<Waypoint>, I get the warning:

Unchecked Cast: kotlin.collections.List to kotlin.colletions.List

I can't figure out a way to implement it otherwise. What's the right way to implement this function without this warning?




In case of generic classes casts cannot be checked because type information is erased in runtime. But you check that all objects in the list are Waypoints so you can just suppress the warning with @Suppress("UNCHECKED_CAST").

To avoid such warnings you have to pass a List of objects convertible to Waypoint. When you're using * but trying to access this list as a typed list you'll always need a cast and this cast will be unchecked.




Is there a way to filter out null Any? values in Kotlin Map?

The filter functions return a Map with the same generic types as the original map. To transform the type of the value, you need to map the values from Any? to Any, by doing a cast. The compiler can't know that the predicate you pass to filter() makes sure all the values of the filtered map are non-null, so it can't use type inference. So your best et is to use

val filtered: Map<String, Any> = map.filterValues { it != null }.mapValues { it -> it.value as Any }

or to define a function doing the filtering and the transformation in a single pass, and thus be able to use smart casts:

fun filterNotNullValues(map: Map<String, Any?>): Map<String, Any> {
    val result = LinkedHashMap<String, Any>()
    for ((key, value) in map) {
        if (value != null) result[key] = value
    }
    return result
}



Related



Tags