So I am learnign kotlin, classes. I get this error in the title. I create a class called USER, within this class there is the field whoIfollow, and his type is USER. Within the USER class there is the whoHeFollows() function, which checks if whoIfollow is null or not.
I did it in 4 different ways, and in two of them it worked, in two of them I got the error. I would like to understand why this is, the theory that explains it. Thanks.
What I found strange is that in my opinion the first and third way should be identical(alsop the others.. but idk i have the feeling these 2 are more similar ), however one generates the error and the other does not... please someone clarify this for me. Thanks in advance.
The code:
fun main(){
class USER(var name: String, val age: Int, var whoIfollow: USER? = null){
/*
These 2 ways work:
==========================================
fun whoHeFollows(): String{
val x = whoIfollow?.nome ?: "nobody"
return "$name follows $x"
}
==========================================
fun whoHeFollows(): String{
val whoIfollow2 = quemEuSigo
if(whoIfollow2!=null){
val x = whoIfollow2.nome
return "$name follows $x"
}
else{return "$name follows nobody"}
}
}
These 2 does not work:
==========================================
fun whoHeFollows(): String{
whoIfollow?.let{
val x = whoIfollow.nome
return "$name follows nobody"
}
}
==========================================
fun whoHeFollows(): String{
if(whoIfollow!=null){
val x = whoIfollow.name
return "$name segue $x"
}
else{return "$name follows nobody"}
}
==========================================
WHY?
*/
}
val x = USER("luiz",25)
val y = USER("joao", 15)
//x.whoIfollow = y
y.whoIfollow = x
println(x.whoHeFollows())
println(y.whoHeFollows())
}
CodePudding user response:
Error message basically explains what is happening here. whoIfollow property is mutable, so after you checked it is not null, some other thread might change it to null and then whoIfollow.nome would result in NullPointerException.
First example works, because ?. operator passes not-null value to the next step. It does not access the property twice. It acquires the property value, checks this value for null and if it is not null then it invokes name on exactly the same value it already checked.
Second example works, because local variable whoIfollow2 can't be modified by anyone, so if it was checked for null already, then it can't change.
Third example would work if you would use it.name instead of whoIfollow.nome. It would be similar to the first example: it acquires the property once and if it is not null, then use the same value again to acquire name.
Fourth can't work. Value of whoIfollow property may change between hoIfollow!=null check and whoIfollow.name.
