I'm initializing a class by loading data from a Map<String, Any>
in Kotlin. As this Map is gleaned directly from JSON, I don't know for certain that any given key exists, or that its value is of the type I expect. To unpack this Map safely I'm doing the following, which appears to work perfectly:
a = rawData["A"] as? String ?: ""
Some of this data is in further nested JSON, which I'm unpacking to Arrays; I've tried to do this in the same way:
b = rawData["B"] as? Array<String> ?: arrayOf<String>()
However, when I attempt this using an array (as above) IntelliJ kicks up a fuss, saying
Warning:(111, 30) Kotlin: Unchecked cast: Any? to Array<String>
Is this just the IDE getting itself in a twist or is this method genuinely unsafe for Arrays despite being seemingly perfectly safe for other types?
In Smart Casting, we generally use is or !is an operator to check the type of variable, and the compiler automatically casts the variable to the target type, but in explicit type casting we use as operator. Explicit type casting can be done using : Unsafe cast operator: as.
There are two ways to define an array in Kotlin. We can use the library function arrayOf() to create an array by passing the values of the elements to the function. Since Array is a class in Kotlin, we can also use the Array constructor to create an array.
In this example, we will see how we can define an ArrayList in Kotlin and add an item in the list. We can do it using the library function add() or we can use the "+=" operator. In order demonstrate, we will be creating two ArrayLists, one is of mutable type and the other is of immutable type.
For any future readers of this question, to expand on the accepted answer with a solution:
To safely cast Any to an array of a particular type in Kotlin, you have to first cast to an untyped array (see zsmb13's answer above for why), and then filter that array to the desired type.
For example, to cast input: Any
to an array of String
instances, you would call:
val inputAsArray = (input as? Array<*>)?.filterIsInstance<String>()
I was ready to call this a bug, because Array
is a reified type, meaning its generic parameter can actually be checked at runtime (unlike a List
, for example). I've tried looking to see if it's been filed yet, and it turns out the compiler is actually right to show you a warning. As you can see in the response to this issue, there's still a nullability problem with casts of this kind.
val a = arrayOf("foo", "bar", null) as Array<String>
println(a[2].length)
Arrays like the one in this example are successfully cast (using as
, they don't throw an exception, using as?
, they don't return null
), however, the cast can not ensure that this is an Array<String>
, only that it's an Array<String?>
.
This means that you can later read null
values from a variable that is typed as an Array<String>
after the cast, with no further warnings from the compiler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With