Reputation: 8728
I'm having trouble understanding the following change to a piece of Kotlin code:
package org.example.kotlin.nulll.resolution
import java.util.*
object UtilResources {
private var properties: Properties? = null
fun loadProperties() {
properties = Properties()
properties?.load(UtilResources.javaClass.getResourceAsStream("/config.properties"))
}
fun getProperties(properties: String): String {
loadProperties()
System.out.println(UtilResources.properties)
System.out.println(UtilResources.properties?.getProperty(properties))
return UtilResources.properties?.getProperty(properties).toString()
}
}
works fine, i.e. returns the property value loaded from config.properties
or "null"
in case the property isn't present in the file.
If I change the code to be null-safe to
object UtilResources {
private val properties: Properties = Properties()
fun loadProperties() {
properties.load(UtilResources.javaClass.getResourceAsStream("/config.properties"))
}
fun getProperties(properties: String): String {
loadProperties()
System.out.println(UtilResources.properties)
System.out.println(UtilResources.properties.getProperty(properties))
return UtilResources.properties.getProperty(properties).toString()
}
}
I'm getting NullPointerException
because UtilResources.properties.getProperty(properties)
is null
which I'm verifying with the System.out.println
Statements.
In the first version properties
is not null
just like in the second, so the ?
operator is the only thing that's changing afaik. However, it's placed after a non-null property, so it shouldn't have any effect.
null.toString()
should always work because it's an overloading extension function in Kotlin.
Assume that config.properties
exists and that UtilResources.javaClass.getResourceAsStream("/config.properties"
returns a non-null value. You can find an SSCCE project at https://gitlab.com/krichter-sscce/kotlin-null-resolution. It doesn't contain more information than this question.
Please note that I'm not seeking debugging support, I'd like to understand what's going on and broaden my understanding of Kotlin. I didn't manage to condense the example further.
I'm using Kotlin 1.4.31 through Maven 3.6.
Upvotes: 3
Views: 270
Reputation: 78
In your first version Kotlin knows that you are calling toString()
on a nullable type, since you are calling getProperty()
on the Nullable field properties
, wherefore Kotlins extension function Any?.toString()
ist used.
In your second version Kotlin doesn't knows that you are calling toString()
on a Nullable type, since you are calling getProperty()
on a field that cannot be null
and the function getProperty()
is a Java function that doesn't defines a Nullable return value. Therefore the extension function isn't used and a NPE is thrown if the property doesn't exists.
The following code works as expected:
object UtilResources {
private val properties: Properties = Properties()
fun loadProperties() {
properties.load(UtilResources.javaClass.getResourceAsStream("/config.properties"))
}
fun getProperties(key: String): String {
loadProperties()
println(properties)
println(properties.getProperty(key))
return properties.getOptionalProperty(key).toString()
}
private fun Properties.getOptionalProperty(key: String): String? = getProperty(key)
}
Upvotes: 3