Reputation: 13
A nullable type can be checked and cast to a non-nullable type, but the other way around is quite difficult.
For example:
str1: String? = ""
// if str1 not null
str2: String = str1
str3: String? = str2 // This works!
In my case I'm talking about a function with an Array parameter in which the contents could be null, but the contents of the Array I want to pass to the function is non-nullable. That does not work:
var var1: Array<String?> = arrayOfNulls(10)
var var2: Array<String> = var1.filterNotNull().toTypedArray()
var var3: Array<String?> = var2 // This does not work!
My question is how to make this work?
I am able to cast the array to a nullable array, but I'm not sure if this is the correct way of doing this.
Upvotes: 1
Views: 1353
Reputation: 170713
No answer actually seems to explain at the moment why arrays are invariant (and so Array<String>
is not a subtype of Array<String?>
). If
var var2: Array<String> = var1.filterNotNull().toTypedArray()
var var3: Array<String?> = var2 // This does not work!
worked, then you could do
var3[0] = null
val x: String = var2[0]
Because var3
and var2
refer to the same object, this puts null
into an Array<String>
and then retrieves it as a non-nullable String
. This obviously breaks null-safety.
It's better to only "cast the array to a nullable array, as you're doing" if you are sure your code can never do this.
Upvotes: 0
Reputation: 2513
what I can say is,
//This value can hold null values
str1: String? = ""
// if str1 not null, store values in str2
// so, now str2 holds NOT NULL VALUES
str2: String = str1
// Now by default since str2 is NOT NULL
// All the values being passed inside str2 will always be NOT NULL
//
str3: String? = str2 // This does not work
str3 will only throw an error in case str2 is null but it is not possible since as you said, it goes through a null check.
the workaround looks something like this.
str1 : String? = ""
str2 : String? = str1
str3 : String? = str2
str1 : String? = ""
str2 : String = str1 ?: ""
str3 : String = str2
Update
As per the updated question,
// A list of nulls
var var1: List<String?> = listOf(null, null, null, null, null, null, null, null, null, null)
//Mutable List to hold not null values or filter out null values
var var2: MutableList<String> = mutableListOf()
for (i in var1) var2.add(i ?: "")
//var3 will always be not null
var var3: List<String?> = var2
Upvotes: 0
Reputation: 11486
In Kotlin, arrays are invariant, which means that an array of a given type can't be assigned to an array of its parent type. That's why you can't assign Array<String>
to Array<String?>
, even if String
is a subclass of String?
. For this to work, you should either
var var1: Array<String?> = arrayOfNulls(10)
var var2: List<String> = var1.filterNotNull()
var var3: List<String?> = var2 // Now works
var var1: Array<String?> = arrayOfNulls(10)
var var2: Array<String> = var1.filterNotNull().toTypedArray()
var var3: Array<String?> = var2 as Array<String?> // Now works
Upvotes: 2
Reputation: 755
var str1: String? = ""
// if str1 not null
var str2: String = str1 ?: ""
var str3: String? = str2
Try This, Here ?: stands for checking if a value is null or not, if not null its fine, but if it gets null you can set a default value in it, that why i used a default value "" in it.
Upvotes: 0