I have a list for example of type People
. My list can contain only elements of type Student
or only elements of type Worker
:
interface People {
val name: String
val age: Int
}
data class Student(
override val name: String,
override val age: Int,
val course: Int
) : People
data class Worker(
override val name: String,
override val age: Int,
val position: String
) : People
At some point I need to know the exact type of the list (student or worker). Can I safely find out the exact type? So far I've written this code, but it doesn't look very good:
fun someLogic(items: List<People>): List<People> {
return (items as? List<Student>) ?: (items as? List<Worker>)
?.filter {}
....
}
Also, I get a warning:
Unchecked cast
Can you please tell me how to perform such transformations correctly?
At runtime, the type parameter you used to create the list is not available. e.g. it is impossible to distinguish between the following two situations:
val students: List<People> = listOf<Student>(student1, student2)
val people: List<People> = listOf<People>(student1, student2)
This is because of type erasure.
The only information you have at runtime that can help determine a list's element type is the type of its elements.
So if a list has no elements, there is no way of knowing what type of list it is. Though in most situations, you don't need to anyway.
So assuming the list can only be a list of all students, or a list of all workers, but not a list containing a mixture of students and workers, you can determine the type of the list by checking the first element.
when (items.firstOrNull()) {
null -> { /* cannot determine the type */ }
is Student -> { /* is a list of students */ }
is Worker -> { /* is a list of worker */ }
// you can remove this branch by making the interface sealed
else -> { /* someone made another class implementing People! */ }
}
If you want to get a List<Student>
or List<Worker>
out of this on the other hand, you can just use filterIsInstance
:
val students = items.filterIsInstance<Student>()
val worker = items.filterIsInstance<Worker>()
whichever list is not empty, then the type of items
is the type of that list.