Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

People also ask

What is unchecked cast in Kotlin?

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 Waypoint s so you can just suppress the warning with @Suppress("UNCHECKED_CAST") .

How do I use a list on Kotlin?

Inside main() , create a variable called numbers of type List<Int> because this will contain a read-only list of integers. Create a new List using the Kotlin standard library function listOf() , and pass in the elements of the list as arguments separated by commas.

How do you stop unchecked cast Kotlin?

1 Answer. Show activity on this post. Adding @Suppress("UNCHECKED_CAST") (also possible through IDEA's Alt + Enter menu) to any of statement, function, class and file should help.

How do you cast objects in Kotlin?

Kotlin explicit casting with the as operator The as operator is used to explicitly convert an object to another type when possible. To perform a safe explicit cast, you need to use the nullable cast as? operator. And that's how you can cast object types with Kotlin.


In Kotlin, there's no way to check the generic parameters at runtime in general case (like just checking the items of a List<T>, which is only a special case), so casting a generic type to another with different generic parameters will raise a warning unless the cast lies within variance bounds.

There are different solutions, however:

  • You have checked the type and you are quite sure that the cast is safe. Given that, you can suppress the warning with @Suppress("UNCHECKED_CAST").

    @Suppress("UNCHECKED_CAST")
    val waypointList = list as? List<Waypoint> ?: return null
    
  • Use .filterIsInstance<T>() function, which checks the item types and returns a list with the items of the passed type:

    val waypointList: List<Waypoint> = list.filterIsInstance<Waypoint>()
    
    if (waypointList.size != list.size)
        return null
    

    or the same in one statement:

    val waypointList = list.filterIsInstance<Waypoint>()
        .apply { if (size != list.size) return null }
    

    This will create a new list of the desired type (thus avoiding unchecked cast inside), introducing a little overhead, but in the same time it saves you from iterating through the list and checking the types (in list.foreach { ... } line), so it won't be noticeable.

  • Write a utility function that checks the type and returns the same list if the type is correct, thus encapsulating the cast (still unchecked from the compiler's point of view) inside it:

    @Suppress("UNCHECKED_CAST")
    inline fun <reified T : Any> List<*>.checkItemsAre() =
            if (all { it is T })
                this as List<T>
            else null
    

    With the usage:

    val waypointList = list.checkItemsAre<Waypoint>() ?: return null
    

To improve @hotkey's answer here's my solution:

val waypointList = list.filterIsInstance<Waypoint>().takeIf { it.size == list.size }

This gives you the List<Waypoint> if all the items can be casted, null otherwise.


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.


I made a little variation to @hotkey answer when used to check Serializable to List objects :

    @Suppress("UNCHECKED_CAST")
    inline fun <reified T : Any> Serializable.checkSerializableIsListOf() =
        if (this is List<*> && this.all { it is T })
          this as List<T>
        else null

Instead of

myGenericList.filter { it is AbstractRobotTurn } as List<AbstractRobotTurn>

I like doing

myGenericList.filter { it is AbstractRobotTurn }.map { it as AbstractRobotTurn }

Not sure how performant this is, but no warnings at least.