问题描述
我无法理解对一段 Kotlin 代码的以下更改:
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()
}
}
工作正常,即返回从 config.properties
或 "null"
加载的属性值,以防文件中不存在该属性。
如果我将代码更改为空安全
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()
}
}
我得到 NullPointerException
,因为 UtilResources.properties.getProperty(properties)
是 null
,我正在用 System.out.println
语句进行验证。
在第一个版本中,properties
与第二个版本中的 null
不同,因此 ?
运算符是唯一改变 afaik 的东西。然而,它被放置在一个非空属性之后,所以它应该没有任何影响。
null.toString()
应该始终有效,因为它是 Kotlin 中的重载扩展函数。
假设 config.properties
存在并且 UtilResources.javaClass.getResourceAsstream("/config.properties"
返回一个非空值。您可以在 https://gitlab.com/krichter-sscce/kotlin-null-resolution 找到 SSCCE 项目。它不包含比这个问题更多的信息。
请注意,我不是在寻求调试支持,我想了解正在发生的事情并拓宽我对 Kotlin 的理解。我没能进一步浓缩这个例子。
我使用的是 Kotlin 1.4.31 到 Maven 3.6。
解决方法
在您的第一个版本中,Kotlin 知道您在可空类型上调用 toString()
,因为您在可空字段 getProperty()
上调用 properties
,因此 Kotlins 扩展函数 {{1} } 已使用。
在您的第二个版本中,Kotlin 不知道您在 Nullable 类型上调用 Any?.toString()
,因为您在一个不能为 toString()
的字段上调用 getProperty()
而函数 { {1}} 是一个未定义 Nullable 返回值的 Java 函数。因此,不使用扩展函数,如果属性不存在,则抛出 NPE。
以下代码按预期工作:
null