一个吗?非空 属性 上的运算符可防止链中出现任何 NullPointerException?
Does an ? operator on a non-null property prevent any NullPointerException in the chain?
我无法理解对一段 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()
}
}
工作正常,即 returns 从 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"
returns 是一个非空值。您可以在 https://gitlab.com/krichter-sscce/kotlin-null-resolution 找到 SSCCE 项目。它不包含比这个问题更多的信息。
请注意,我不是在寻求调试支持,我想了解正在发生的事情并拓宽我对 Kotlin 的理解。我没能进一步压缩示例。
我正在使用 Kotlin 1.4.31 到 Maven 3.6。
在您的第一个版本中,Kotlin 知道您在可空类型上调用 toString()
,因为您在可空字段 properties
上调用 getProperty()
,因此 Kotlin 扩展函数 Any?.toString()
已使用。
在你的第二个版本中,Kotlin 不知道你在调用 toString()
一个 Nullable 类型,因为你在一个不能是 null
的字段上调用 getProperty()
并且function getProperty()
是一个 Java 函数,它没有定义 Nullable return 值。因此,如果 属性 不存在,则不使用扩展函数并抛出 NPE。
以下代码按预期工作:
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)
}
我无法理解对一段 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()
}
}
工作正常,即 returns 从 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"
returns 是一个非空值。您可以在 https://gitlab.com/krichter-sscce/kotlin-null-resolution 找到 SSCCE 项目。它不包含比这个问题更多的信息。
请注意,我不是在寻求调试支持,我想了解正在发生的事情并拓宽我对 Kotlin 的理解。我没能进一步压缩示例。
我正在使用 Kotlin 1.4.31 到 Maven 3.6。
在您的第一个版本中,Kotlin 知道您在可空类型上调用 toString()
,因为您在可空字段 properties
上调用 getProperty()
,因此 Kotlin 扩展函数 Any?.toString()
已使用。
在你的第二个版本中,Kotlin 不知道你在调用 toString()
一个 Nullable 类型,因为你在一个不能是 null
的字段上调用 getProperty()
并且function getProperty()
是一个 Java 函数,它没有定义 Nullable return 值。因此,如果 属性 不存在,则不使用扩展函数并抛出 NPE。
以下代码按预期工作:
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)
}